Разработка EJB
В качестве примера будет реализован EJB компонент “Perfect Time” из предыдущего раздела, посвященного RMI. Пример будет выполнен как Сессионный Компонент без Состояния.
Как упоминалось ранее, EJB компоненты содержат не менее одного класса (EJB) и двух интерфейсов: Удаленный и Домашний интерфейсы. Когда вы создаете Удаленный интерфейс для EJB, вы должны следовать следующим принципам:
Вот простой удаленный интерфейс для PerfectTime EJB:
//: c15:ejb:PerfectTime.java
//# Вы должны установить J2EE Java Enterprise
//# Edition с java.sun.com и добавить j2ee.jar
//# в вашу переменную CLASSPATH, чтобы скомпилировать
//# этот файл. Подробности смотрите на java.sun.com.
// Удаленный интерфейс для PerfectTimeBean
import java.rmi.*; import javax.ejb.*;
public interface PerfectTime extends EJBObject { public long getPerfectTime() throws RemoteException; } ///:~
Домашний интерфейс является фабрикой для создания компонента. Он может определить метод create, для создания экземпляра EJB, или метод finder, который находит существующий EJB и используется олько для Сущностных Компонент. Когда вы создаете Домашний интерфейс для EJB, вы должны следовать следующим принципам:
Стандартное соглашение об именах Домашних интерфейсов состоит в прибавлении слова “Home” в конец имени Удаленного интерфейса. Вот Домашний интерфейс для PerfectTime EJB:
//: c15:ejb:PerfectTimeHome.java
// Домашний интерфейс PerfectTimeBean.
import java.rmi.*; import javax.ejb.*;
public interface PerfectTimeHome extends EJBHome { public PerfectTime create() throws CreateException, RemoteException; } ///:~
Теперь вы можете реализовать бизнес логику. Когда вы создаете вышу реализацию EJB класса, вы должны следовать этим требованиям (обратите внимание, что вы должны обратиться к спецификации EJB, чтобы получить полный список требований при разработке Enterprise JavaBeans):
//: c15:ejb:PerfectTimeBean.java
// Простой Stateless Session Bean,
// возвращающий текущее системное время.
import java.rmi.*; import javax.ejb.*;
public class PerfectTimeBean implements SessionBean { private SessionContext sessionContext; //возвращае текущее время
public long getPerfectTime() { return System.currentTimeMillis(); } // EJB методы
public void ejbCreate() throws CreateException {} public void ejbRemove() {} public void ejbActivate() {} public void ejbPassivate() {} public void setSessionContext(SessionContext ctx) { sessionContext = ctx; } }///:~
Из-за простоты этого примера EJB методы (ejbCreate( ), ejbRemove( ), ejbActivate( ), ejbPassivate( )) оставлены пустыми. Этиметоды вызываются EJB Контейнером и используются для управления состоянием компонента. Метод setSessionContext( ) передает объект javax.ejb.SessionContext, который содержит информацию относительно контекста компонента, такую как текущая транзакция и информация безопасности.
После того, как мы создали Enterprise JavaBean, нам нужно создать описатель развертывания. Описатель развертывания - это XML файл, котрый описывает EJB компонент. Описатель развертывания должен хранится в файле, называемом ejb-jar.xml.
//:! c15:ejb:ejb-jar.xml
<?xml version="1.0" encoding="Cp1252"?> <!DOCTYPE ejb-jar PUBLIC '-
//Sun Microsystems, Inc. //DTD Enterprise JavaBeans 1.1 //EN' 'http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd'>
<ejb-jar> <description>Example for Chapter 15</description> <display-name></display-name> <small-icon></small-icon> <large-icon></large-icon> <enterprise-beans> <session> <ejb-name>PerfectTime</ejb-name> <home>PerfectTimeHome</home> <remote>PerfectTime</remote> <ejb-class>PerfectTimeBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> <ejb-client-jar></ejb-client-jar> </ejb-jar> ///:~
Вы можете видеть, что Компонент, Удаленный интерфейс и Домашний интерфейс определены внури ярлыка <session> этого описателя развертывания. Описатель развертывания может быть сгенерирован автоматически при использовании инструментов разработки EJB.
Наряду со стандартным описателем развертывания ejb-jar.xml, спецификация EJB устанавливает, что любые ярлыки, специфичные для производитея, должны хранится в отдельном файле. Это обеспечивает высокую совместимость между компонентами и EJB контейнерами различных марок.
Файлы должны быть заархивированы внутри стандартного Java Archive (JAR) файла. Описатель развертывания должен помещаться внутри поддиректории /META-INF Jar.
После того, как EJB компонент определен в описателе развертывания, установщик может развернуть EJB компонент в EJB Контейнере. В то время ,когда это писалось, процесс установки был достаточно “GUI визуализированным” и специфичным для каждого индивидуального EJB Контейнера, так что этот обзор не документирует этот процесс. Однако каждый EJB Контейнер имеет хорошую документацию для равзертывания EJB.
Поскольку EJB компоненты являются распределенными компонентами, процесс установки должен также создавать некотые клиентские якоря для вызова EJB компонент. Эти классы должны помещаться в classpath клиентского приложения. Поскольку EJB компоненты могут реализовываться поверх RMI-IIOP (CORBA) или RMI-JRMP, генерируемые якоря могут различаться в зависимости от EJB Контейнера, тем не менее, они являются генерируемыми классами.
Когда клиентмкая программа хочет вызвать EJB, она должна найти EJB компонент внутри JNDI и получить ссылку на домашний интерфейс EJB компонента. Домашний интерфейс используется для создания экземпляра EJB.
В этом примере клиентская программа - это простая Java программа, но вы должны помнить, что она так же легко может быть сервлетом, JSP или даже распределенным объектом CORBA или RMI.
//: c15:ejb:PerfectTimeClient.java
// Клиентская программа для PerfectTimeBean
public class PerfectTimeClient { public static void main(String[] args) throws Exception { // Получение контекста JNDI с помощью
// JNDI службы Указания Имен:
javax.naming.Context context = new javax.naming.InitialContext(); // Поиск Домашнего интерфейса в
// службе JNDI Naming:
Object ref = context.lookup("perfectTime"); // Приведение удаленного объекта к домашнему итерфейсу:
PerfectTimeHome home = (PerfectTimeHome) javax.rmi.PortableRemoteObject.narrow( ref, PerfectTimeHome.class); // Создание удаленного объекта из домашнего интерфейса:
PerfectTime pt = home.create(); // Вызов getPerfectTime()
System.out.println( "Perfect Time EJB invoked, time is: " + pt.getPerfectTime() ); } } ///:~
Последовательность выполняемых действий поясняется комментариями. Обратите внимание на использование метода narrow( ) для совершения приведения объекта перед выполнением Java приведения. Это очень похоже на то, что происходит в CORBA. Также обратите внимание, что Домашний объект становится фабрикой для объекта PerfectTime.