Первый пример EJB был предназначен для того, чтобы показать вам все и каждую линию кода, необходимые для реализации EJB. В процессе, вы также увидели, что вам необходимо, как минимум, четыре исходных файла, содержание которых должно быть синхронизировано. Даже в проектах среднего размера такое расположение тесно связанных файлов может легко стать неуправляемым или, как минимум, нанести ущерб производительности разработчика.
Ясно, что мы нуждаемся в инструменте, снижающем количество работы, требуемое для совмещения всех этих кусков вместе. Такой инструмент существует и может быть получен как "мастер", который интегрирован во многие коммерческие среды разработки EJB.
Тем не менее существует другая возможность, которую мы будем использовать в этой главе. Это XDoclet - инструмент с открытым исходным кодом, который вы можете загрузить с веб-сайта SourceForge.net. XDoclet на самом деле является связкой двух разных инструментов: WebDoclet, о котором я не буду рассказывать здесь, и EJBDoclet.
Оба эти инструмента дают преимущества при использовании Doclet API, это то же самое, на чем базируется JavaDoc. JavaDoc читает ваш исходный код и использует исходники Java, комментарии Java и специальные тэги для генерации HTML документации ваших классов. EJBDoclet читает исходные файлы с определением вашего класса реализации компонента, и, вместо генерации HTML файлов, он генерирует исходные файлы Java с определением интерфейсов компонента, и XML файлы для дескриптора развертки и конфигурационной информации, специфичной для Контейнера. EJBDoclet может также генерировать другие классы поддержки, но я не буду рассказывать об этом здесь.
EJBdoclet достаточно мощный инструмент, который может значительно упростить процесс разработки, не только потому, что он генерирует исходный код для вашей прользы, но также потому, что он может быть привлечен программно с помощью Ant скриптов, демонов сборки или других утилит Java, таким образом, он может стать частью полностью автоматизированного процесса сборки.
Однако это отнимает некоторое время и терпение, чтобы заставить EJBDoclet работать правильно в первый раз, обычно потому, что в этом инструменте очень много настроек. Я не буду объяснять, как работает EJBDoclet, я просто покажу кое-что из того, что он может сделать для вас. Большинство из Ant скриптов этой главы используют EJBDoclet, как часть процесса сборки, и если вы решите использовать EJBDoclet в ваших собственных проектах, вы можете найти его очень сложным поначалу. Но будьте терпеливы и потратьте несколько дней на эксперименты с ним: польза, которую вы получите от EJBDoclet, возвратит их вам с избытком.
Основной механизм EJBDoclet'а очень прост: вы предоставляете класс реализации компонента, насыщенный специальными тегами в ваших JavaDoc комментариях, а EJBDoclet сгенерирует все остальные исходные файлы, которые дополнят ваш EJB в соответствии с вашими инструкциями.
EJBDoclet также сгенерирует реализацию по умолчанию для методов оповещения Контейнера, которые вы должны, в противном случае, кодировать руками в вашем классе реализации компонента. Однако, так как EJBDoclet не может и не должен изменять ваш исходный код, дополнительный код реализации, сгенерированный EJBDoclet'ом, будет унаследован от предоставленного вами класса. Класс реализации, сгенерированный EJBDoclet'ом, который унаследует весь ваш код, станет реальным классом, который будет использоваться контейнером.
Ваш класс реализации должен быть объявлен абстрактным, и если вы предоставите реализацию любого метода уведомления Контейнера, сгенерированный EJBDoclet'ом класс будет передавать вызов в вашу реализацию. Пожалуйста, обратите внимание, что когда вы используете EJBDoclet, ваши классы реализации будут абстрактными независимо от типа компонента, реализуемого вами, в то время, как в нашем первом примере класс MovieBean был абстрактным потому, что для CMP entity bean в EJB 2.x определена абстрактная модель программирования.
Ниже приведена новая версия реализации класса компонента Movie, для которой будет использоваться EJBDoclet. Этот код расположен в директории c18/example05/src/ejb-tier. Пожалуйста, обратите внимание, что нет исходного кода для интерфейсов компонента и для дескриптора развертки в этом примере, так как они будут сгенерированы EJBDoclet'ом.
//: c18:example05:src:ejb-tier:javatheater:ejb:implementation:MovieBean.java
package
javatheater.ejb.implementation;
import
javax.ejb.*;
import
java.util.Collection;
/**
* Это реализация
<code>
Movie
</code>
entity bean.
*
@see
javatheater.ejb.MovieHome
* @ejb:bean
* name="Movie"
* jndi-name="javatheater/Movie"
* type="CMP"
* primkey-field="id"
* reentrant="False"
* @ejb:pk class="java.lang.Integer"
* @ejb:home remote-class="javatheater.ejb.MovieHome"
* @ejb:interface remote-class="javatheater.ejb.Movie"
* @ejb:finder signature=
* "java.util.Collection findByTitle(java.lang.String title)"
*/
public abstract class
MovieBean
implements
EntityBean
{
/**
* Проверяет первичный ключ и инициализирует
* поля компонента.
* @ejb:create-method
*/
public
Integer ejbCreate
(
Integer id, String title
)
throws
CreateException
{
if
(
id ==
null
)
throw new
CreateException
(
"Primary key cannot be null"
)
;
if
(
id.intValue
()
==
0
)
throw new
CreateException
(
"Primary key cannot be zero"
)
;
setId
(
id
)
;
setTitle
(
title
)
;
return null
;
}
public
void
ejbPostCreate
(
Integer id, String title
) {
}
/**
* Возвращает идентификатор Movie, который также является первичным ключом
* Movie.
* @ejb:pk-field
* @ejb:persistent-field
* @ejb:interface-method
*/
abstract public
Integer getId
()
;
/**
* Этот метод не является частью удаленного интерфейса.
*/
abstract public
void
setId
(
Integer id
)
;
/**
* Возвращает заголовок Фильма.
* @ejb:persistent-field
* @ejb:interface-method
*/
abstract public
String getTitle
()
;
/**
* Устанавливает заголовок Фильма.
* @ejb:persistent-field
* @ejb:interface-method
*/
abstract public
void
setTitle
(
String title
)
;
}
// /:~
Посмотрите на приведенный выше код, вы должны заметить, что есть три значительных преимущества в использовании EJBDoclet'а:
- Приведенный выше код является только исходным файлом, который вам нужен для реализации вашего компонента. Здесь нет файлов определения интерфейса, нет дескриптора развертки, нет XML файлов, специфичных для контейнера.
- Приведенный выше класс содержит только код, который имеет значение для вас - здесь нет "заплаток", типа методов уведомления Контейнера.
- Вы не определяете метод findByPrimaryKey(…). EJBDoclet всегда генерирует этот метод за вас, так как он требуется спецификацией EJB, но другие поисковые методы вы должны определить явно (более подробно об этом я расскажу позднее).
В этом Java коде нет ничего нового. Наиболее интересная часть содержится в комментариях, которые насыщают ваш код мета-информацией, которую использует EJBDoclet для генерации кода.
Все тэги, начинающиеся с ejb, являются комментариями EJBDoclet'а. Например, тэг ejb:bean вы используете, чтобы предоставить информацию о всем компоненте целиком, это такая информация, как тип, EJB имя, JNDI имя, поле первичного ключа и многое другое. Другие теги, такие как ejb:interface-metod, вы используете для предоставления информации, которая применяется к определенной части компонента. В данном случае это метод, который вы хотите показать в компонентном интерфейсе компонента. Более полное описание того, что означает каждый тэг можно найти в руководстве по EJBDoclet'у.
Однако, сами по себе теги не предоставляют всей информации, требующейся для генерации кода исходных файлов. Например, тэги не указывают в каком директории должны генерироваться файлы, или как они должны быть вызваны. Эта дополнительная информация передается в EJBDoclet в то время, когда он запускает задачу Ant. Ниже приведен отрывок из скрипта Ant из директории этого примера:
<ejbdoclet sourcepath="${ejb.source.dir};${gen.source.dir}" destdir="${gen.source.dir}" excludedtags="@version, @author" ejbspec="2.0"> <fileset dir="${ejb.source.dir}"> <include name="**/*Bean.java" /> </fileset> <classpath> <path refid="server.classpath" /> <path refid="xdoclet.classpath" /> </classpath> <deploymentdescriptor destdir="${gen.source.dir}/META-INF" /> <homeinterface /> <localhomeinterface /> <remoteinterface /> <localinterface /> <entitycmp /> <session /> <jboss destdir="${gen.source.dir}/META-INF" /> </ejbdoclet>
Есть два интересных свойства EJBDoclet, которые показаны в этой задаче Ant: первое из них состоит в том, что вы можете решить, какой версии спецификации EJB будут удовлетворять сгенерированные файлы. Другими словами, значение параметра ejbspec может быть либо "1.1", либо "2.0", а EJBDoclet сгенерирует XML дескрипторы и соответствующие Java файлы. Второе свойство состоит в том, что вы можете указать какие элементы вы хотите сгенерировать и как. В приведенной выше задаче элементы, начиная от <deploymentdescriptor> до <jboss> определяют, какие исходные файлы назначено генерировать EJBDoclet'у, и где они должны быть (если вы не хотите использовать расположение по умолчанию). Определенно, мы инструктируем EJBDoclet сгенерировать за нас: дескриптор развертки, домашний и компонентный интерфейсы для локального и удаленного представления компонента (если это также запрашивается ejb: тэгами в исходных файлах), класс реализации entity bean, класс реализации session bean и все XML файлы, необходимые для JBoss (пожалуйста, обратите внимание, что EJBDoclet также поддерживает генерацию специфичных для Контейнера файлов для некоторых различных EJB Контейнеров).
Теперь вы имеете представление о том, что EJBDoclet может делать за нас, и мы будем использовать его во всех наших следующих примерах в этой главе. Прежде чем продолжить, я хотел бы, чтобы вы собрали example05 и проверили содержимое директория sub, куда будут переданы все сгенерированные исходные файлы, чтобы лучше понимать процесс сборки и работу EJBDoclet'а.
← | Клиентское EJB приложение | Реализация session bean | → |