Компонентная объектная модель JavaBeans
Программное обеспечение Программное обеспечение

Главная>Программное обеспечение>Компонентная объектная модель JavaBeans
Программное обеспечение Тема номера

Компонентная объектная модель JavaBeans

Дата публикации:
20.12.1997
Посетителей:
640
Просмотров:
612
Время просмотра:
2.3
Накопление и использование программистских знаний — ключевой вопрос современных информационных технологий. Сейчас не имеет большого значения, насколько удобно в том или ином инструментальном окружении проектировать и реализовывать программы "с нуля" — в любом случае для большой информационной системы это будет сложный, многолетний процесс. Впрочем, как правило, это и не нужно. Очень многие вещи уже написаны (причем по многу раз), так что остается только настроить их должным образом и "проинтегрировать", то есть собрать в единую систему.

 

Если проводить аналогию со строительством, то в настоящее время наиболее перспективными представляются крупноблочные сборочные технологии. В программировании это направление развивается давно и под разными названиями — библиотеки стандартных программ, пакеты прикладных программ и т.п. Разработаны многочисленные "маги", реализующие фрагменты, специфичные для операционного окружения или предметной области.

 

Компонентные объектные среды — это наиболее современный и естественный фундамент для накопления и использования программистских знаний. Подобная среда базируется на компонентной объектной модели и включает в себя готовые компоненты, а также инструментальное окружение, позволяющее выбрать подходящие компоненты, настроить их и связать между собой, объединив в готовое приложение.

 

Компонентные объектные среды обладают всеми достоинствами, присущими объектно-ориентированному подходу:

 

  • инкапсуляция объектных компонентов скрывает сложность реализации, делая видимым только предоставляемый вовне интерфейс;
  • наследование позволяет развивать созданные ранее компоненты, не нарушая целостность объектной оболочки;
  • полиморфизм по сути дает возможность группировать объекты, характеристики которых с некоторой точки зрения можно считать сходными.

 

Кроме того, объединение компонентов в рамках единого контейнера, с одной стороны, позволяет строить иерархии с небольшим числом сущностей на каждом уровне (это необходимое условие успешной работы с любой сложной системой), а, с другой стороны (и это очень важно с методологических позиций), предоставляет механизм образования новых понятий как во время разработки программной системы, так и в процессе ее использования.

 

JavaBeans — не единственная и не первая компонентная объектная среда, однако, учитывая огромную популярность Java-технологии, мы решили рассмотреть именно JavaBeans, сосредоточившись на компонентной объектной модели. Наше изложение основывается на версии спецификации JavaBeans [1] от 25 июля 1997 года. Используются также некоторые другие спецификации и их проекты [2], [3], [4], [5].

 

Коротко о языке Java

 

Мы позволим себе коротко напомнить читателям некоторые сведения о языке Java, которые понадобятся нам для дальнейшего изложения. Более полное описание языка и ассоциированной технологии можно найти, например, в статье [6].

 

Java — объектно-ориентированный язык. В его основе лежит понятие класса. Класс является шаблоном для создания объектов; он может содержать данные и методы. Существуют различные режимы доступа к элементам класса — private, protected, public.

 

Java — полностью объектно-ориентированный язык, каждому понятию которого (класс, объект, метод и т.п.) соответствует класс, поддерживающий программную обработку соответствующих "понятийных" объектов.

 

Классы в языке Java объединяются в пакеты. Каждый пакет определяет отдельное пространство имен. Все классы, входящие в один пакет, являются дружественными по отношению друг к другу, то есть имеют взаимный доступ к переменным и методам, если противное не оговорено явно посредством спецификаторов private или protected.

 

Для обозначения наследования используется ключевое слово extends. Класс Object — это корень дерева наследования. Имеется предопределенная иерархия классов, описанная в пакете java.lang.

 

В языке Java отсутствует множественное наследование, однако наличие понятия интерфейса позволяет смягчить это ограничение. Интерфейс представляет собой набор описаний методов. Классы могут реализовывать интерфейсы. Этот факт обозначается ключевым словом implements в заголовке класса.

 

Класс Class используеятся для получения во время выполнения информации о "классовых" свойствах объектов. Типичные методы этого класса — forName (получение объекта класса Class по текстовому имени), newInstance (порождение нового объекта данного класса), getMethods (получение массива объектов, описывающих public-методы класса, в том числе унаследованные).

 

Java-классы могут быть абстрактными, то есть не до конца конкретизированными. Это означает, что в классе описаны методы, определения которых отсутствуют. Такие методы (как и сам класс) должны снабжаться описателем abstract и конкретизироваться в производных классах.

 

Для обработки исключительных ситуаций, возникающих во время выполнения программы, в языке Java используется конструкция try/catch/finally. Для передачи информации об исключительной ситуации используются объекты классов — наследников класса Throwable.

 

Механизм потоков — обязательная черта современных операционных сред. В языке Java потоки представлены посредством класса Thread, интерфейса Runnable, спецификатора метода synchronized и методов класса Object wait и notify.

 

Java-программы подразделяются на два вида — самостоятельные приложения и аплеты. Последние выполняются в среде Web-навигатора и могут поступать по сети. Приложения и аплеты существенно различаются по мерам безопасности, принимаемым в процессе их работы (аплеты контролируются значительно жестче).

 

Java-компилятор транслирует исходные тексты программ в коды виртуальной Java-машины. Компилятор порождает файлы классов, содержащие интерпретируемые коды и дополнительную информацию, используемую на этапе выполнения. Спецификации Java-машины обеспечивают независимость скомпилированных программ от поддерживающей аппаратно-программной платформы.

Основные понятия модели JavaBeans

 

Среда JavaBeans является надстройкой над стандартной Java-технологией. Она наследует понятия и характеристики Java, такие как объектная ориентированность, многопотоковость, использование виртуальной машины, независимость от аппаратно-программной платформы, информационная безопасность и т.п. В JavaBeans нет ничего, не выразимого в терминах языка Java.

 

Основой среды JavaBeans является компонентная объектная модель, представляющая собой совокупность архитектуры и прикладных программных интерфейсов. Архитектуру образуют основные понятия и связи между ними. Прикладные программные интерфейсы характеризуют набор сервисов, предоставляемых элементами среды. Они описываются в терминах синтаксиса и семантики Java-классов и интерфейсов.

 

К числу основных понятий архитектуры JavaBeans относятся компоненты и контейнеры. Контейнеры могут включать в себя множество компонентов, образуя общий контекст взаимодействия с другими компонентами и с окружением. Контейнеры могут выступать в роли компонентов других контейнеров.

 

Неформально компонент ("кофейное зерно" — Java Bean) можно определить как многократно используемый программный объект, допускающий обработку в графическом инструментальном окружении и сохранение в долговременной памяти. С реализационной точки зрения компонент — это Java-класс и, возможно, набор ассоциированных дополнительных классов.

 

Каждый компонент предоставляет набор методов, доступных для вызова из других компонентов и/или контейнеров.

 

Компоненты могут обладать свойствами. Совокупность значений свойств определяет состояние компонента. Свойства могут быть доступны на чтение и/или запись посредством методов выборки и установки.

 

Компоненты могут порождать события (быть источниками событий), извещая о них другие компоненты, зарегистрировавшиеся в качестве подписчиков. Извещение (называемое также распространением события) заключается в вызове определенного метода объектов-подписчиков.

 

Типичным примером события является изменение свойств компонента. В общем случае компонент может предоставлять подписку на получение информации об изменении и на право запрещать изменение.

 

Методы, свойства и события образуют набор афишируемых характеристик компонента, то есть характеристик, доступных инструментальному окружению и другим компонентам. Этот набор может быть выяснен посредством механизма интроспекции.

 

Состояние компонентов может быть сохранено в долговременной памяти. Наличие методов для подобного сохранения выделяет компоненты JavaBeans среди произвольных Java-классов.

 

Компоненты JavaBeans могут упаковываться для более эффективного хранения и передачи по сети. Описание соответствующего формата является частью спецификаций JavaBeans.

 

Жизненный цикл компонентов JavaBeans можно подразделить на три этапа:

 

  • разработка и реализация компонента;
  • сборка приложения из компонентов;
  • выполнение приложения.

 

Разработка и реализация компонентов JavaBeans по сути не отличается от создания произвольных Java-объектов, хотя и может включать реализацию специфических методов.

 

Сборка приложений выполняется, как правило, в инструментальном окружении, позволяющем проанализировать афишируемые характеристики компонентов, настроить значения свойств, зарегистрировать подписку на получение событий, организовав тем самым взаимодействие компонентов. Разработчик компонента может реализовать специальные методы для использования исключительно в инструментальном окружении (например, редактор свойств).

 

Компоненты взаимодействуют между собой и с инструментальным окружением. Взаимодействие осуществляется двумя способами - вызывом методов и распространением событий.

 

Спецификации JavaBeans описывают только локальное взаимодействие компонентов, осуществляемое в пределах одной виртуальной Java-машины. (Напомним, впрочем, что Java-аплеты рассчитаны на передачу по сети, так что возможно собрать приложение из компонентов, первоначально распределенных по сети.) Удаленные объекты могут связываться по протоколам архитектуры CORBA [7], с помощью удаленного вызова методов (Remote Method Invocation — RMI) или иными способами, не относящимися к области действия спецификации JavaBeans (Рис. 1).

 

Рисунок 1. Нелокальное взаимодействие компонентов.

 

Далее мы подробно рассмотрим, как описанные основные понятия реализуются в среде JavaBeans.

 

Афиширование и выяснение интерфейсов

 

В среде JavaBeans существуют способы динамического (то есть не по исходным текстам) выяснения характеристик компонентов. К таким характеристикам относятся:

 

  • методы, доступные для вызова другими компонентами и инструментальным окружением;
  • свойства, которые можно опрашивать и/или изменять;
  • события, порождаемые данным компонентом.

 

Подобное выяснение в терминологии JavaBeans называется интроспекцией.

 

Интроспекция используется прежде всего на этапе разработки, в рамках инструментального окружения, позволяя увидеть афишируемые характеристики и с их помощью настроить компонент и связать его с другими элементами приложения.

 

Принципиальная возможность интроспекции была изначально заложена в Java-технологии. Файлы классов содержат достаточно информации для выяснения всех необходимых характеристик объектов. Воспользоваться этой информацией можно с помощью класса Class, пакета java.lang.reflect и некоторых других средств, которые будут рассмотрены далее. Чтобы оценить полноту сведений, предоставляемых Java-средой, целесообразно рассмотреть фрагменты описаний класса Class (Листинг 1), а также класса Method из пакета java.lang.reflect (Листинг 2).

 

Листинг 1
Листинг 2

 

Таким образом, разработчики и пользователи компонентов ведут работу исключительно Java-средствами. Более того, в большинстве случаев разработчику, чтобы сделать класс полноценным элементом среды JavaBeans, достаточно придерживаться определенной дисциплины описания методов, не прибегая к явному афишированию характеристик. Например, по умолчанию в число афишируемых попадают все public-методы компонента.

 

Способность компонента среды JavaBeans по существу без дополнительных усилий со стороны разработчика предоставлять информацию о своем интерфейсе называется рефлексией. Рефлексия базируется на дисциплине определения методов. Эта дисциплина состоит в следовании заданным шаблонам при выборе имен методов, а также типов формальных параметров и результатов. Далее, по ходу изложения, мы будем приводить эти шаблоны.

 

Среда JavaBeans проектировалась таким образом, чтобы в типичных случаях и действия разработчиков, и внутренняя реализация оставались простыми; дополнительные усилия и утяжеление компонентов должны требоваться только тогда, когда этого желает сам программист. В данном случае, если разработчику не хватает выразительной силы рефлексии, он может реализовать интерфейс BeanInfo, явным образом описывающий афишируемые характеристики компонента.

 

Интерфейс BeanInfo содержит методы, позволяющие получить объекты-описатели характеристик компонента. В число этих методов входят getBeanDescriptor, getMethodDescriptors и т.д. (см. Листинг 3 и Листинг 4). Поскольку реализация методов может быть сколь угодно изощренной, у разработчика появляется возможность ассоциировать с компонентом ресурсы (например, файлы), содержащие описательную информацию. Класс SimpleBeanInfo, входящий в пакет java.beans, является "пустой" реализацией интерфейса BeanInfo, отрицающей наличие у компонента каких-либо афишируемых методов, свойств и событий. Разработчик может создать производный класс и выборочно переопределить методы класса SimpleBeanInfo.

 

Листинг 3
Листинг 4

 

Класс Introspector реализует процесс интроспекции. По заданному компоненту он конструирует объект класса BeanInfo (см. Листинг 5). Действует Introspector следующим образом. Сначала он пытается найти класс, имя которого получается из имени класса компонента приписыванием текста "BeanInfo". Если такой класс находится, а его методы возвращают непустые дескрипторы, соответствующая информация используется при конструировании результирующего объекта BeanInfo. В противном случае Introspector полагается на механизм рефлексии и анализирует имена и типы параметров public-методов класса компонента и его предшественников.

 

Листинг 5

 

Характерная особенность Java-технологии состоит в наличии стройной модели безопасности. Применительно к интроспекции действуют два защитных рубежа:

 

  • Получение объектов Field, Method и Constructor возможно только путем применения методов класса Class, которые вызывают системный менеджер безопасности.
  • Доступ к полям и методам объектов производится с применением стандартных правил языка Java.


Кроме того, аплеты подвергаются дополнительному контролю.

 

Детальный анализ модели безопасности Java выходит за рамки данной статьи. Здесь мы отметим лишь, что компонентная объектная среда не привносит каких-либо новых, специфических угроз, поскольку она полностью описывается в терминах языка Java.

 

Механизм событий

 

Согласно спецификациям JavaBeans, у каждого события есть источник и, быть может, один или несколько подписчиков (получателей).

 

Источник обязан:

 

  • выбрать имя метода, вызываемого в компонентах-подписчиках при распространении события. Этот метод должен содержаться в интерфейсе, который является расширением интерфейса EventListener (данное расширение мы будем называть интерфейсом события);
  • реализовать метод регистрации подписчиков события и метод аннулирования регистрации;
  • при распространении события вызвать метод, описанный в интерфейсе события, во всех компонентах-подписчиках.

 

В свою очередь, подписчик должен предпринять следующие действия:

 

  • выполнить реализацию интерфейса события, то есть по сути реализовать метод обработки события (напомним, что имя этого метода выбрал источник);
  • зарегистрироваться в качестве подписчика события.

 

Рассмотрим перечисленные шаги более подробно.

 

Действия, выполняемые источником события

 

Источник события по своему выбору назначает имя метода, вызываемого в компонентах-подписчиках при распространении события. Чтобы сделать возможной автоматическую интроспекцию компонентов на предмет распространяемых ими событий (то есть для поддержки рефлексии), данный метод описывается в расширении пустого интерфейса java.util.EventListener, играющего роль этикетки. Пример расширения приведен на Листинг 6.

 

 

Листинг 6

 

По соглашению, опять-таки направленному на поддержку рефлексии, имя интерфейса-расширения должно оканчиваться цепочкой символов "Listener".

 

Если источник желает распространять несколько различных событий, допускается описание в одном интерфейсе соответствующего числа методов их обработки.

 

Метод обработки события должен иметь один аргумент, которым является так называемый событийный объект — преемник класса java.util. EventObject. Посредством этого объекта подписчику передается информация об источнике и другие характеристики события. Определение класса EventObject приведено на Листинг 7. Листинг 8 содержит возможное описание класса KeyPressedEvent (окончание "Event" - еще одно требование рефлексии).

 

Листинг 7
Листинг 8

 

Реализация методов регистрации подписчиков, аннулирования регистрации, а также собственно распространения события может быть выполнена способом, приведенным на Листинг 9. Отметим, что при распространении события вызов методов подписчиков производится синхронным образом, в рамках потока источника события.

 

Листинг 9

 

Обратим внимание на два аспекта программного текста, приведенного на Листинг 9. Во-первых, в источнике необходимо обеспечить безопасность работы в многопотоковой среде. Методы add/remove выполняются в рамках потоков подписчиков, поэтому они нуждаются в синхронизации. В методе fire также следует учитывать возможность регистрационных действий параллельно с распространением события. Отсюда три вхождения ключевого слова synchronized.

 

Во-вторых, регистрационные методы должны поддерживать рефлексию и определяться по следующим шаблонам:

 

Листинг 10

 

Определение метода fire — внутреннее дело источника события.

 

Действия, выполняемые подписчиком события


Реализация интерфейса события — основное действие, выполняемое подписчиком. Его содержательная сторона зависит от специфики подписчика. Чисто технические моменты отражены на Листинг 11.

 

Листинг 11

 

Регистрация подписки производится обращением к соответствующему add-методу источника события.

 

Рисунок 2. Схема взаимодействия источника и подписчиков события.

 

 

Общая схема взаимодействия источника и подписчиков события представлена на Рис. 2. Если проводить аналогию с обычной подпиской на газеты и журналы, то базовый механизм, описанный в спецификациях JavaBeans, соответствует оформлению подписки в редакции каждого издания (а не в отделении связи). В спецификациях упоминается также о возможности реализации адаптеров — посредников, берущих на себя централизованное оформление подписки и реализацию определенной дисциплины распространения событий. При наличии адаптера схема взаимодействия источников и подписчиков событий может выглядеть так, как показано на Рис. 3. Очевидно, подобная схема облегчает жизнь всем взаимодействующим сторонам (не считая адаптера, который необходимо реализовать).

 

Рисунок 3. Схема взаимодействия источников и подписчиков при наличии адаптера.

 

При установлении взаимодействия между источниками и подписчиками событий значительная часть работы может быть выполнена инструментальной средой. Эта среда может сгенерировать код, содержащий обращение к add-методам, обеспечить согласованность названий методов обработки событий, сгенерировав при необходимости вспомогательные классы, и т.п.

 

Некоторые комментарии


При проектировании механизма событий разработчикам спецификаций JavaBeans пришлось учитывать целую гамму требований:

 

  • механизм должен естественным образом интегрироваться в Java-среду;
  • механизм событий должен быть простым и для реализации, и для использования;
  • механизм должен быть расширяемым, поддерживать разные модели распространения событий;
  • механизм должен допускать интеграцию с другими компонентными средами.


Таким образом, задача перед разработчиками стояла трудная, и, на наш взгляд, они не сумели найти достаточно хорошего решения, допустив ряд методологических просчетов.

 

Если есть система, содержащая n источников событий и m подписчиков, то при использовании базового механизма число связей, которые необходимо поддерживать, имеет порядок n * m. Это много. Напомним, что одним из основных побудительных мотивов развития объектных технологий было понижение внутренней сложности программных систем путем обеспечения относительной независимости компонентов. Использование адаптеров позволяет уменьшить количество связей до величины порядка n + m, однако оно нуждается в стандартизации.

 

Предлагаемый механизм событий плохо параметризуется, прежде всего потому, что имена методов обработки фиксируются на уровне исходных текстов. Из-за этого трудно писать программы, систематически обрабатывающие различные события. Приходится как минимум наращивать объем программ, что вступает в противоречие с основными положениями Java-технологии.

 

Пространство событий не структурировано, хотя некоторые действия в некоторых частях среды Java (например, в абстрактном оконнном инструментарии, AWT) в этом направлении предприняты. Возможность иерархической организации элементов - одно из необходимых условий успешного создания и сопровождения сложных систем. Здесь это условие нарушено (конечно же, иерархии классов в данном случае недостаточно).

 

Складывается впечатление, что в предлагаемом виде механизм событий является слишком простым, в нем не хватает ряда понятий. По существу это способ диспетчеризации вызовов методов. Какая-либо "событийность" в такой трактовке попросту отсутствует. Обычно события возникают с частотой, определяемой факторами, внешними по отношению к программной системе, так что необходимо минимизировать по крайней мере время распространения события. При предлагаемом синхронном вызове методов оценить время распространения не представляется возможным. Более того, необходимо позаботиться о противодействии атакам на доступность, производимым путем регистрации подписчика, метод обработки которого не возвращает управления. Часть этих проблем можно решить, реализовав интеллектуальный многопотоковый адаптер, но тогда придется отдельно решать вопросы безопасности, так как ряд защитных мер в Java-технологии основан на прослеживании стека вызовов, и опасность может грозить со стороны зловредного источника событий.

 

При подготовке спецификаций JavaBeans пришлось пересмотреть механизм событий, первоначально предусматривавшийся абстрактным оконным инструментарием. Весьма возможно, что и версия 1.01 спецификаций JavaBeans не является в этом смысле окончательной. Впрочем, для систем небольшого и среднего масштаба она представляется вполне удовлетворительной.

 

 

Свойства компонентов

 

Свойства компонентов (такие как цвет изображения, размер и т.п.) можно представлять себе в виде полей объектов; в большинстве случаев так они и реализуются. Тем не менее, спецификации JavaBeans, в соответствии с последовательным объектно-ориентированным подходом, предусматривают доступ к свойствам только посредством специальных методов выборки и установки, так что в принципе свойства могут быть устроены сколь угодно сложным образом.

 

Между свойствами разных компонентов могут существовать связи двоякого рода. Во-первых, при изменении одного свойства может потребоваться модификация других свойств или иных характеристик. Такие свойства называются связанными. Во-вторых, некоторые изменения могут трактоваться как некорректные и запрещаться. Соответствующие свойства называются ограниченными. Тем самым спецификации JavaBeans предоставляют средства контроля целостности объектной среды.

 

Свойства компонентов могут подвергаться настройке. Обычно настройка производится в инструментальном окружении при сборке приложений, однако, вообще говоря, она может осуществляться и во время выполнения.

 

Перейдем к детальному рассмотрению заявленных тем.

 

Методы и события, ассоциированные со свойствами

 

Свойства компонентов могут быть скалярными и индексируемыми. Выборка и установка скалярных свойств осуществляется с помощью методов get/set:

 

Листинг 12

 

Например, если свойством компонента является цвет, соответствующие методы могут описываться как

 

Листинг 13

 

Особый шаблон предусмотрен для выборки булевых свойств:

 

Листинг 14

 

Вообще говоря, свойства могут быть доступны только на чтение или только на запись; тогда для них определяется лишь один из методов — get или set соответственно.

 

Индексируемые свойства образуют массивы с целочисленными индексами. С этими массивами можно работать покомпонентно или как с единым целым. Шаблоны соответствующих методов и их примеры приведены на Листинг 15 (под <типом_свойства> здесь понимается тип элемента массива).

 

Листинг 15

 

Спецификации JavaBeans предусматривают наличие связанных свойств, после изменения которых возбуждается событие propertyChange. Другие компоненты могут подписаться на это событие и, следовательно, получать информацию о производимых изменениях, анализируя объект-параметр PropertyChangeEvent, фрагмент описания которого приведен на Листинг 16.

 

Листинг 16

 

Метод propertyChange, вызываемый для обработки изменения значения свойства, описан в интерфейсе PropertyChangeListener (Листинг 17). Источник события, в соответствии с общими правилами (см. Разд. Механизм событий), должен реализовать методы addPropertyChangeListener и removePropertyChangeListener, обеспечивая регистрацию подписчиков.

 

Листинг 17

 

Вспомогательный класс PropertyChangeSupport, входящий в пакет java.beans, реализует рутинные действия, характерные для обслуживания связанных свойств (см. Листинг 18). Естественно, разработчики компонентов могут воспользоваться этим классом.

 

Листинг 18

 

Помимо связанных, спецификации JavaBeans описывают ограниченные свойства, перед изменением значений которых распространяется событие vetoableChange с параметром PropertyChangeEvent. Подписчики этого события могут отклонить планируемое изменение, возбудив исключительную ситуацию PropertyVetoException. Метод set должен отреагировать на подобное вето, вернув прежнее значение, "извинившись" перед уже оповещенными подписчиками (то есть вызвав их методы vetoableChange с обратной парой новое/старое значение) и передав исключительную ситуацию инициатору изменения. Соответственно, заголовок set-метода для ограниченных свойств приобретает следующий вид:

 

Листинг 19

 

Синтаксически связанные и ограниченные свойства аналогичны, но реализация последних требует гораздо большей аккуратности и от источников (set-методов), и от подписчиков события vetoableChange. Источнику рекомендуется воспользоваться вспомогательным классом java.beans.VetoableChangeSupport, аккуратно выполняющим все необходимые действия. Подписчикам будет проще, если сделать свойство и ограниченным, и связанным. В таком случае до изменения (при обработке события vetoableChange) подписчики заботятся только о голосовании "за" и "против", а после изменения (при обработке события propertyChange) они выясняют, каким же стало новое значение.

 

Настройка свойств


Компонент объектной среды особенно полезен тогда, когда его можно настроить. Обычно настройка выполняется во время сборки приложения в инструментальном окружении.

 

Для несложных компонентов можно представить себе схему настройки, при которой окружение путем интроспекции выявляет афишируемые свойства и порождает электронный бланк, каждая клетка которого соответствует одному свойству. Редактирование содержимого клетки выполняется соответствующим редактором свойства. Редакторы свойств, принадлежащих стандартным типам, входят в Java-окружение; в более сложных случаях должен существовать специализированный редактор, поставляемый с компонентом или с инструментальным окружением.

 

Класс-редактор свойства должен реализовывать интерфейс PropertyEditor (см. Листинг 20). Обязательными для реализации являются метод setValue () и один из методов прорисовки и редактирования свойства — в графическом или текстовом представлении. По общим правилам, при изменении значения свойства редактор должен возбуждать событие propertyChange. Отсюда необходимость в реализации методов add/remove.

 

Листинг 20

 

Для установления ассоциаций между типами данных и их редакторами служит класс PropertyEditorManager. Он поддерживает каталог зарегистрированных редакторов; если же явная регистрация отсутствует, PropertyEditorManager пытается отыскать класс, имя которого образовано приписыванием к имени типа текста "Editor" (см. Листинг 21).

 

Листинг 21

 

Для настройки сложных компонентов с большим числом специфических свойств может потребоваться специализированный класс, облегчающий действия пользователей по сравнению со стандартным редактированием бланка. Такой класс-настройщик должен быть прямым или косвенным преемником класса java.awt.Component, одновременно реализуя интерфейс java.beans. Customizer (описание последнего приведено на Листинг 22).

 

Листинг 22

 

Чтобы известить окружение о наличии настройщика, компонент должен предоставлять класс BeanInfo и, в частности, реализовывать метод getCustomizerClass класса BeanDescriptor (см. Разд. Афиширование и выяснение интерфейсов).

 

На наш взгляд, механизм свойств специфицирован в среде JavaBeans весьма квалифицированно. В простых ситуациях разработчику компонента не нужно делать ничего; в сложных же случаях он имеет практически полную свободу для самых изощренных реализаций.

Сохранение компонентов в долговременной памяти

 

Сохранение и восстановление компонентов

 

Среда JavaBeans полагается на стандартные механизмы сохранения Java-объектов. Таких механизмов два. Интерфейс java.io. Serializable (см. Листинг 23) предусматривает сохранение в стандартной форме графа объектов, доступных из данного. Впрочем, методы writeObject/readObject и здесь предоставляют пользователям определенную свободу. Интерфейс java.io.Externalizable (см. Листинг 24) делает эту свободу абсолютной — Java-машина берет на себя лишь сохранение классовой информации, все остальное отдается на откуп пользователю. Реализация интерфейса Externalizable целесообразна в первую очередь тогда, когда есть необходимость представить компонент JavaBeans как элемент другой объектной среды, такой, например, как OLE или OpenDoc.

 

Листинг 23

 

 

Листинг 24

 

При сохранении объектов в долговременной памяти приходится учитывать стандартные проблемы, связанные с различным временем жизни компонентов, с изменением их версий и с обеспечением их информационной безопасности; мы, однако, на этих проблемах останавливаться не будем.

 

Создание нового экземпляра компонентов также сопряжено с некоторыми тонкостями. Экземпляр может создаваться в разных контекстах, например, в контексте приложения или в контексте инструментального окружения. Метод instantiate класса java.beans.Beans (см. Листинг 25) наделен достаточным интеллектом, чтобы учесть контекст и сделать все корректно; в этой связи пользователю рекомендуется избегать создания экземпляров иными методами.

 

Листинг 25

 

Помимо instantiate, класс Beans содержит некоторые другие методы, облегчающие управление компонентами объектной среды (см. Листинг 25).

 

Упаковка компонентов


Упаковка сохраненных Java-объектов (и, в частности, компонентов объектной среды) важна прежде всего для эффективной доставки их по сети. Спецификации JavaBeans рекомендуют (но не предписывают) использовать для упаковки формат JAR (Java-архив).

 

Java-архивы могут содержать файлы классов, результаты сериализации объектов, изображения, справочную информацию и другие ресурсы. С архивом может быть ассоциирован manifest-файл, описывающий его содержимое, в том числе зависимости между компонентами.

 

На примере сохранения компонентов можно видеть, насколько упрощается жизнь разработчиков за счет продуманной организации Java-технологии. Проблема сохранения решена на уровне стандартного Java-окружения, так что все надстройки (такие как JavaBeans) могут полагаться на существующие механизмы.

 

Компоненты и контейнеры

 

Представляется удивительным, что спецификация [3], регламентирующая фундаментальное отношение компоненты/контейнер, не вошла в число первоочередных и дорабатывается только сейчас, в рамках новой версии JavaBeans с рабочим названием Glasgow.

 

Механизм контейнеров необходим для достижения по крайней мере двух целей:

 

  • организации иерархической логической структуры компонентов в рамках объектной среды;
  • организации единого контекста для совокупности компонентов, предоставляющего им набор сервисов для взаимодействия между собой и с окружением.

 

Первый пункт означает, в частности, инкапсуляцию совокупности компонентов, так что с точки зрения окружения она выглядит как единое целое с набором методов, предоставляемых контейнером. Кроме того, применительно к иерархической структуре возможен систематический обход и обработка ее элементов.

 

Второй пункт имеет противоположное назначение — инкапсуляцию окружения. Контейнер выступает в роли оболочки, скрывающей от компонентов особенности внешней среды и предоставляющей им свой контекст.

 

Чтобы избежать употребления перегруженного в Java-среде термина "контейнер", авторы спецификации употребляют сочетание "BeanContext". Мы не будем этого делать, поскольку, помимо предоставления общего контекста, у контейнера есть и другие функции; надеемся, что к путанице это не приведет.

 

Реализация механизма контейнеров использует служебный интерфейс java.util.Collection, который предполагается включить в одну из ближайших версий Java-среды. Фрагмент описания этого интерфейса, содержащий типичные методы для работы с наборами, приведен на Листинг 26.

 

Листинг 26

 

 

Интерфейс java.beans.BeanContextChild содержит описания методов, позволяющих ассоциировать с компонентом объемлющий контейнер и опрашивать эту ассоциацию (см. Листинг 27). Таким образом, связи, ведущие вниз (от контейнера к компоненту), обслуживает интерфейс Collection, а связи, ведущие вверх, — интерфейс BeanContextChild.

 

Листинг 27

 

 

С отношением компоненты/контейнер ассоциировано событие beanContextChanged. Соответствующий интерфейс (BeanContextListener) описан на Листинг 28.

 

Листинг 28

 

 

Вообще говоря, распространение этого события может происходить в несколько приемов: контейнер, получив извещение от компонента, передает его своим подписчикам, в число которых, вероятно, входит объемлющий контейнер, и т.д. Чтобы распознать подобные "вторичные" события и определить первоисточник, предусмотрены соответствующие методы событийного объекта BeanContextEvent (см. Листинг 29).

 

Листинг 29

 

 

Изменения совокупности компонентов, входящих в контейнер, обслуживает событийный объект BeanContextMembershipEvent. Он содержит информацию о разности ("дельте") между старым и новым составом контейнера, то есть о том, какие компоненты были добавлены или, напротив, удалены (Листинг 30).

 

Листинг 30

 

Интегрирующим элементом рассматриваемой спецификации является интерфейс java.beans.BeanContext, описывающий связи, идущие как вверх, так и вниз (за счет расширения интерфейсов BeanContextChild и Collection соответственно). Интерфейс BeanContext позволяет также опросить предоставляемые контейнером сервисы и ресурсы. Содержит он и методы для регистрации подписчиков событий (см. Листинг 31).

 

 

Листинг 31

 

Разумеется, кроме синтаксиса специфицируется семантика методов интерфейса BeanContext.

 

При добавлении компонента методом add (), унаследованным у интерфейса Collection, контейнер "привязывает" этот компонент к себе, вызывая в нем метод setBeanContext с аргументом this (полноценные компоненты должны реализовывать интерфейс BeanContextChild). В свою очередь, компонент может протестовать против включения в контейнер, возбуждая исключительную ситуацию PropertyVetoException. Если это случится, контейнер обязан отменить добавление, возбудив исключительную ситуацию IllegalArgumentException. При успешном добавлении компонента контейнер распространяет подписчикам событие beanContextChanged с соответствующим объектом-параметром. Контейнер должен подписаться у нового компонента на события, связанные со свойствами последнего, чтобы отслеживать по крайней мере свойство beanContext и не допустить нарушения целостности иерархической структуры. Кроме того, компонент регистрируется как подписчик событий, возбуждаемых контейнером.

 

При удалении объекта из контейнера производятся обратные действия. В частности, вызывается метод setBeanContext с аргументом null. Если компонент находится в состоянии, не позволяющем произвести удаление, он возбуждает исключительную ситуацию PropertyVetoException, заставляя тем самым контейнер отказаться от удаления.

 

Отметим, что контейнерная реализация методов интерфейса Collection должна быть безопасной в многопотоковой среде.

 

Рассмотренная спецификация заполняет очень важную методологическую брешь в JavaBeans. Хотелось бы надеяться, что переход к новой версии прикладного программного интерфейса Java, включающей интерфейс BeanContext, произойдет в ближайшее время.

 

Обмен данными

 

Компоненты объектной среды обычно взаимодействуют не только с объемлющим контейнером, но и между собой. Механизм событий - это одна грань такого взаимодействия. В дополнение необходима возможность обмена структурированными элементами данных.

 

Соответствующая спецификация [5] готовится специалистами компаний Sun Microsystems и Lotus Development. И хотя совместная работа только началась, мы сочли необходимым осветить выдвинутые предложения ввиду исключительной важности затрагиваемой темы.

 

Центральным понятием предлагаемых спецификаций является информационная шина. Компоненты могут подключаться к шине, помещать на нее данные (это делают поставщики) и считывать данные (это делают потребители). Обмен носит асинхронный характер: поставщик, поместив данные, не заботится о том, когда они будут считаны. Для идентификации элементов данных используются их имена.

 

Информационная шина описывается классом InfoBus. Методы этого класса (реализуемого в рамках виртуальной Java-машины) порождают экземпляры шины, осуществляют подключение компонентов к подходящим экземплярам, отслеживают список шин и подключенных к ним компонентов, распространяет события, обслуживающие обмен данными, и т.п. Фрагмент описания класса InfoBus представлен на Листинг 32. 

 

Листинг 32

 

 

Процесс информационного взаимодействия компонентов в спецификациях InfoBus можно подразделить на пять фаз:

 

  • подключение к шине;
  • прослушивание шины;
  • установление контакта между поставщиком и потребителем, передача элемента данных;
  • выяснение формата элемента данных;
  • интерпретация элемента данных.


Для подключения к шине компонент должен реализовать интерфейс InfoBusMember, получить ссылку на экземпляр шины и войти в число ее членов. Фрагмент интерфейса InfoBusMember приведен на Листинг 33. Обратим внимание, что шина, ассоциируемая с компонентом, трактуется как его свойство, изменение значения которого может отслеживаться на основе механизма событий.

 

 

Листинг 33

 

Для облегчения реализации интерфейса InfoBusMember спецификации предлагают класс InfoBusMemberImpl, который, в дополнение к "обязательным", предоставляет еще два удобных метода — joinInfoBus () и leaveInfoBus () (см. Листинг 34).

 

 

Листинг 34

 

Для реализации второй фазы (прослушивание шины) поставщик должен подписаться на информацию о запросах данных, воспользовавшись методом addDataProducer () класса InfoBus. Аналогично, потребитель должен подписаться на информацию о наличии данных, обратившись к методу addDataConsumer (). Компонент может одновременно являться и поставщиком, и потребителем (типичный пример — промежуточное звено конвейера).

 

Третью фазы информационного взаимодействия компонентов обслуживают преимущественно событийные объекты. В соответствии с моделью, принятой в спецификации InfoBus, поставщик оповещает потребителей о появлении нового элемента данных. Потребители запрашивают у поставщиков данные, когда в них возникает нужда. Обмен элементом данных становится возможным, если поставщик и потребитель используют для него одно и то же имя. Ответственность за надлежащий выбор имен лежит на разработчике приложения.

 

Класс InfoBusEvent является базовым для событийных объектов поставки/приема. Его описание приведено на Листинг 35.

 

 

Листинг 35

 

Поставщик объявляет о наличии новых данных, рассылая всем потребителям шины событийный объект класса InfoBusItemAvailableEvent. Методы этого класса позволяют получить информацию о поставщике и ассоциированный элемент данных.

 

Потребитель, желающий получить данные, рассылает объект класса InfoBusItemRequestedEvent, описание которого приведено на Листинг 36. Обратим внимание на метод setDataItem, позволяющий поставщику, получившему событийный объект, "привязать" к нему элемент данных, выдав его тем самым инициатору запроса.

 

Листинг 36

 

Формат элемента данных определяется интерфейсами, которые этот элемент реализует. Базовым интерфейсом элементов данных является DataItem, в число преемников которого входят CollectionAccess, DbAccess и др. Поскольку проблема обмена структурированными данными уже решена в рамках абстрактного оконного инструментария (пакет java.awt.datatransfer), представляется естественным и в спецификациях InfoBus пойти тем же путем, что и было сделано.

 

Спецификации InfoBus только начали свой путь к официальному утверждению. Многие детали еще не определены. Тем не менее, основополагающие решения приняты, и они представляются весьма удачными. В частности, понятие экземпляра шины позволяет структурировать пространство поставщиков и потребителей, уменьшая сложность системы и повышая эффективность обмена данными.

 

Агрегирование интерфейсов

 

В разных ситуациях компонент объектной среды должен поворачиваться к пользователю разными гранями. Например, в инструментальном окружении необходимо получать информацию об афишируемых характеристиках объекта. В настоящее время такую информацию предоставляет специальный информационной объект, косвенно (по имени класса) ассоциированный с исследуемым и реализующий интерфейс BeanInfo. Однако более естественной была бы не косвенная, а прямая ассоциация, позволяющая единообразно осуществлять доступ к разным "проявлениям" объектов.

 

Решению сформулированной задачи служит очень важная в концептуальном плане спецификация [4]. Центральное место в ней занимает понятие агрегата — сущности, обладающей "многогранным" поведением, динамически унаследованным у совокупности классов (интерфейсов). В агрегат входят представители соответствующих классов, а также координатор, способный по запросу выдавать нужного представителя.

 

Спецификации не предусматривают внесения каких-либо изменений в язык Java. Агрегат и входящий в него координатор представлены интерфейсом Aggregate (см. Листинг 37). Интерфейс Aggregate содержит методы, позволяющие получить ссылку на объект требуемого класса и опросить поддерживаемый агрегатом набор классов.

 

Листинг 37

 

Формально каждый представитель является самостоятельным объектом, принадлежащим своему классу, однако с идейной точки зрения более правильно считать, что метод getInstanceOf () возвращает разные проявления одного (агрегатного) объекта.

 

Заключение

 

Спецификации JavaBeans в совокупности с предлагаемыми дополнениями образуют целостную архитектуру компонентной объектной среды, позволяющей накапливать и многократно использовать программистские знания. Уникальным достоинством JavaBeans является Java-фундамент, предоставляющий современный объектный язык, гарантирующий мобильность и информационную безопасность разрабатываемого программного обеспечения.

 

Компоненты среды JavaBeans оказываются мобильными вдвойне. Мост к ActiveX автоматически "вкладывает" их в эту среду, а средства Java IDL помогают организовать взаимодействие с CORBA-брокерами объектных запросов.

 

Разработка спецификаций JavaBeans следовала и следует традициям открытости, заложенным на предыдущих этапах развития Java-технологии. Партнерами JavaSoft в этой работе выступали такие известные компании, как Apple Computer, Borland International, IBM, Informix Software, Lotus Development, Netscape Communications, Novell, Oracle, Silicon Graphics, Sybase, Texas Instruments и многие другие. Спецификации доступны для свободного ознакомления, внесения замечаний и предложений.

 

Политика партнерства способствовала созданию многочисленных инструментальных окружений, поддерживающих процессы разработки и интеграции компонентов JavaBeans. Назовем Data Director for Java (Informix Software), Visual Age for Java (IBM), BeanMachine (Lotus Development), Cosmo Code (Silicon Graphics). На подходе JBuilder (Borland International), Visual JavaScript (Netscape Communications), Java Studio и Java Workshop (SunSoft), PowerJ (Sybase) и др.

 

Разработчики, делающие ставку на JavaBeans, не рискуют проиграть. Эта компонентная объектная среда вступает в пору зрелости, обладая всеми качествами, необходимыми для успешного продвижения.

 

Литература

 

  1. Sun Microsystems -- The JavaBeans 1.01 specification , July, 1997
  2. Sun Microsystems -- Java Core Reflection. API and Specification, February, 1997
  3. L. Cable -- A Draft Proposal to define an Extensible Runtime Containment and Services Protocol for JavaBeans (Version 0.97) -- JavaSoft , August, 1997
  4. L. Cable -- A Draft Proposal for a Object Aggregation/Delegation Model for JavaBeans (Version 0.8) -- JavaSoft, August, 1997
  5. Sun Microsystems, Inc -- InfoBus Specification. Draft Version 0.04 (First Public Review) , July, 1997
  6. Александр Таранов , Владимир Цишевский -- Java как центр архипелага -- Jet Info, 9, 1996
  7. Юрий Пуха -- Объектные технологии построения распределенных информационных систем -- Jet Info, 16, 1997

Уведомления об обновлении тем – в вашей почте

Java в три года

Более трех лет назад, в мае 1995 года, было официально объявлено о появлении в компании Sun Microsystems новой технологии создания сетевых систем – технологии Java, основными составляющими которой стали язык программирования, виртуальная ...

Операционная среда Sun Solaris

В данной статье описывается операционная среда Solaris 2.6, Solaris-серверы, инструментарий для разработки программного обеспечения, а также средства для развертывания и администрирования информационных сетей. В первом разделе излагается точка ...

Разработка модульных приложений на Java

Если необходимо разработать модульную архитектуру на языке Java, поможет OSGi (Open Services Gateway Initiative

Объектные технологии построения распределенных информационных систем

Разработка корпоративных информационных систем (ИС) является одной из крупнейших проблем в информационных технологиях.   Основной принцип управления любой сложной системой был известен давно: "devide et impera" — "разделяй и властвуй". ...

XML и Java в трактовке корпорации Oracle

В первом номере информационного бюллетеня Jet Info за 2000 год была опубликована статья , посвященная языкам разметки документов. Большая часть статьи касалась языка XML (eXtensible Markup Language), не сходящего ныне со страниц компьютерных ...

Облачный подход к разработке

Облачные технологии и сервисы меняют подход разработчиков к построению информационных систем

Современные технологии создания программного обеспечения (обзор)

Основные особенности и проблемы современных программных проектов      Накопленный к настоящему времени опыт создания систем ПО показывает, что это сложная и трудоемкая работа, требующая высокой квалификации участвующих в ней ...

Мониторинг бизнес-приложений: экономим 50 млн рублей в час

Сколько стоит час простоя бизнес-приложений? Что умеют и чего не умеют АРМ-решения? Как пилот может сократить стоимость внедрения?

Искусство управления высокотехнологичными проектами

Проектная команда как симфонический оркестр. Чем слаженнее музыканты, тем чище исполнение. Как этого добиться?

Спасибо!
Вы подписались на обновления наших статей
Предложить
авторский материал





    Спасибо!
    Вы подписались на обновления наших статей
    Подписаться
    на тему







      Спасибо!
      Вы подписались на обновления наших статей
      Оформить
      подписку на журнал







        Спасибо!
        Вы подписались на обновления наших статей
        Оформить
        подписку на новости







          Спасибо!
          Вы подписались на обновления наших статей
          Задать вопрос
          редактору








            Оставить заявку

            Мы всегда рады ответить на любые Ваши вопросы

            * Обязательные поля для заполнения

            Спасибо!

            Благодарим за обращение. Ваша заявка принята

            Наш специалист свяжется с Вами в течение рабочего дня