![]() |
|
||
|
|
|
Enterprise JavaBeans. Часть 5(Гопалан Суреш Рай) Создание многоуровневых приложений - создание Entity-бина Для реализации примера с созданием виртуального книжного online-магазина "Лошади и конюшня" вначале необходимо будет разработать компонент, который мы назовём entity-бин. Для использования в качестве тележки для покупок мы создадим бин-перечень. Наш entity-бин-перечень должен иметь методы для получения и установки аттрибутов названий книг, которые продаёт наш магазин. Он так же может иметь возможность запрашивать такие данные как цена или индекс ISBN. Традиционной последовательностью разработки entity-бина считается следующий порядок:
А теперь детально разберём каждый пункт. Установите свои исходные данные Для примера программы нам потребуется таблица базы данных под названием BOOKS (КНИГИ). Соответствующий язык манипуляции данными (DML) для создания такой таблицы приводится в Примере 5: CREATE TABLE BOOKS CODE Number (КОД Число) *primary key (CODE) Пример 5: Язык DML для таблицы BOOKS Определите свой EJBhome-интерфейс Клиенты EJB не работают напрямую с entity-бином для создания строк или доступа к данным, а скорее создают экземпляр home-интерфейса. Этот интерфейс расширяет javax.ejb.EJBHome и включает в себя методы, которые определяют, каким образом создаётся и где в контейнере располагается entity-бин. Он также подчиняется правилам RMI в том, что аргументы и возвращаемые типы для каждого из методов должны быть сериализуемыми, а методы должны посылать в качестве одного из своих исключений java.rmi.RemoteException. В Примере 6 приводится определение такого интерфейса: package com.gopalan.Shop.Books; import javax.ejb.*; import java.rmi.*;
public interface BooksHome extends EJBHome {
Books create (int isbn, String title, String authors, double price, int discount) throws CreateException, RemoteException; Books findByPrimaryKey (BooksPK book) throws FinderException, RemoteException; } Пример 6: Определение BooksHome-интерфейса Метод create() соответствует методу ejbCreate() в entity-бине. Установки параметров в обоих методах идентичны. Когда клиент вызывает BooksHome.create(), контейнер находит экземпляр entity-бина и вызывает BooksHome.ejbCreate(). Для управляемых контейнером entity-бинов метод ejbCreate()возвращает void, в отличие от случаев управляемой контейнером персистентности, когда он возвращает исходный key object. Первое, что делает клиент, это с помощью JNDI находит home-объект для требуемого бина. BooksHome-интерфейс содержит методы create(), которые будут вызываться всегда, когда клиенту понадобится новый бин. Заметьте, что этот метод реализуется в EJBHome и всякий раз при своей инициализации вызывает метод ejbCreate(). Определите свой EJBremote-интерфейс После того как создаётся экземпляр реализации home-интерфейса, сервер EJB создаёт экземпляры реализации remote-интерфейса и самого бина. В качестве методов в этом интерфейсе используются внешние интерфейсы нашего BooksBean. Сигнатуры методов в этом внешнем интерфейсе идентичны тем, что принадлежат бину, за исключением того, что эти методы посылают java.rmi.RemoteException. Наш entity-бин не реализует этот интерфейс напрямую. Реализацией этого интерфейса занимается соответствующий сгенерированный контейнером код EJBObject. EJBObject действует как proxy, пересылая вызовы методов экземпляру бина, установленному на сервере. Данный remote-интерфейс показан в Примере 7: package com.gopalan.Shop.Books; import javax.ejb.*; import java.rmi.*;
public interface Books extends EJBObject {
public int getIsbn () throws RemoteException; public String getTitle () throws RemoteException; public String getAuthors () throws RemoteException; public double getPrice () throws RemoteException; public int getDiscount () throws RemoteException; public double getDiscountedPrice () throws RemoteException; public void setPrice (double cost) throws RemoteException; public void setDiscount (int disc) throws RemoteException; } Пример 7: Определение remote-интерфейса для бина Books Обратите внимание, что remote-интерфейс бина Books расширяет javax.ejb.EJBObject и объявляет принадлежащие бину BooksBean методы get/set. Он также подчиняется правилам RMI в том, что аргументы и возвращаемые типы каждого метода должны быть Serializable, а методы должны посылать в качестве одного из своих исключений java.rmi.RemoteException. Определите свой исходный ключевой класс Сервер EJB требует, чтобы у entity-бина был исходный ключевой класс (primary key class) с открытым элементом (или элементами) исходных данных. Вы можете сделать так, чтобы бин управлялся контейнером, или написать код, чтобы управлять бином лично. В приведенном ниже примере бин управляется контейнером. В Примере 8 показано определение BooksPK Primary Key Class. package com.gopalan.Shop.Books;
public class BooksPK implements java.io.Serializable {
public int code;
public BooksPK () {
}
public BooksPK (int isbn) {
code = isbn; } } Пример 8: Определение класса BooksPK Primary Key Исходным ключевым классом в таблице BOOKS выступает CODE, поэтому code определён как открытый элемент в данном классе, которому во время создания класса приписывается какое-либо значение. Реализация entity-бина Данный enterprise bean реализует javax.ejb.EntityBean и выбранные разработчиком методы интерфейса. Он должен соответствовать правилам RMI в том, что все аргументы и возвращаемые типы каждого из методов должны сериализовываться, а методы должны в качестве одного их своих исключений посылать java.rmi.RemoteException. Пример 9 показывает реализацию нашего BooksBean: package com.gopalan.Shop.Books; import java.rmi.*; import javax.ejb.*;
public class BooksBean implements EntityBean {
EntityContext entityContext; public int code; // CODE public String title; // TITLE public String authors; // AUTHORS public double price; // PRICE public int discount; // DISCOUNT // Implementation for all the Remote Interface business methods
public int getIsbn () throws RemoteException {
return code; }
public String getTitle () throws RemoteException {
return title; }
public String getAuthors () throws RemoteException {
return authors; }
public double getPrice () throws RemoteException {
return price; }
public int getDiscount () throws RemoteException {
return discount; }
public double getDiscountedPrice () throws RemoteException {
double deduct = ((double)discount)/100; return ( price*(1-deduct) ); }
public void setPrice (double cost) throws RemoteException {
price = cost; }
public void setDiscount (int disc) throws RemoteException {
discount = disc; } // Implementation for all the Home Interface methods public void ejbCreate (int isbn, String bookTitle, String author, double cost, int disc)
throws CreateException, RemoteException {
code = isbn; title = bookTitle; authors = author; price = cost; discount= disc; } public void ejbPostCreate (int isbn, String bookTitle, String author,
double cost, int disc) {
} // Implement all the mandatory methods required by the EJB Spec
public void ejbActivate () throws RemoteException{}
public void ejbLoad () throws RemoteException{}
public void ejbPassivate () throws RemoteException{}
public void ejbRemove () throws RemoteException, RemoveException{}
public void ejbStore () throws RemoteException{}
public void setEntityContext (EntityContext context)
throws RemoteException {
entityContext = context; }
public void unsetEntityContext () throws RemoteException {
entityContext = null; } } Пример 9: Имплементация класса бина BooksBean Обратите внимание, что все методы, составляющие remote-интерфейс, и методы для создания и поиска, составляющие home-интерфейс, были реализованы в этом enterprise Bean. Скомпилируйте свои классы для EJB Все исходники, которые Вы написали, теперь можно скомпилировать. Приступайте. javac *.java Задекларируйте описания развертывания бина С этого момента всё, что мы здесь обсуждаем, будет относиться к реализации данного конкретного серверного бина. Сервер HomeBase производства Iona требует, чтобы наши описание были выполнены на XML. (Сведения по XML Вы можете почерпнуть из любой посвященной этой теме книги. Детальное описание природы XML не входит в цели данной статьи.) Данные свойства используются как при генерации классов контейнеров, так и для их установки и выполнения. Нам необходимо определить определённое количество свойств, которые помогут сгенерировать классы контейнера. В файле свойств (назовём его Shop.ejbml) введите текст, указанный в Примере 10: <!----------------------------------------------------------> <!------- Books Entity Bean ----------------> <!----------------------------------------------------------> <ejbml> <entity-bean name="Books" descriptor="Books/BooksDeployment" package="com.gopalan.Shop.Books" home="com.gopalan.Shop.Books.BooksHome" remote="com.gopalan.Shop.Books.Books" bean="com.gopalan.Shop.Books.BooksBean" primary-key="com.gopalan.Shop.Books.BooksPK" tx-attribute="TX_SUPPORTS" > <property name="databasePassword" value="mouse" /> <property name="dataSourceName" value="Shop" /> <property name="databaseUser" value="user" /> <property name="databaseTable" value="books" /> <container-managed storage-helper= "com.ejbhome.generator.helpers.RelationalPersistenceCodeHelper" table="books" data-source="Shop" user="user" password="mouse" > <field name="discount" /> <field name="price" /> <field name="authors" /> <field name="title" /> <field name="code" /> </container-managed> </entity-bean> </ejbml> Listing 10: Описание развёртывания Books EJB Первые несколько строк указывают на имя наших home и remote-интерфейсов и подчеркивают, что это entity-бин. В этом же файле мы также объявили наш Primary Key class. Так как это управляемый контейнером бин, мы определяем поля базы данных, которыми управляет контейнер. А также в транзактных аттрибутах бина мы указываем, что наш бин поддерживает транзакции (TX_SUPPORTS). Транзактные аттрибуты, которые можно указать, приведены в Таблице 3.
Таблица 3: Транзактные аттрибуты Так как enterprise bean управляется контейнером, мы указываем поля, которые управляются контейнером, чтобы средство разработки могло правильно сгенерировать код для JDBC. Затем мы указываем имя источника данных, имя таблицы и пароль, который может быть полезен при обрашениях нашего бина через JDBC. Зарегистрируйте и установите бин Специфика данного пунка будет зависеть от типа сервера/контейнера EJB, которым Вы пользуетесь. Сервер EJBHome отсылает к файлам datasource.properties и ejbhome.properties, расположенным в директории под именем conf. Вам нужно модифицировать файл datasource.properties, как показано в Примере 11: # This is a list of datasource names with their respective JDBC databases URLs. Пример 11: Определение исходных данных для установки и применеия бина на HomeBase Сгенерируйте классы контейнера Теперь с помощью прилагаемого к серверу/контейнеру средства нужно сгенерировать классы контейнера. Когда entity-бин и session-бин установлены, создаётся несколько файлов для исходников и классов контейнера, которые получают следующие префиксы. Контейнер - это набор классов, сгенерированных средством выполнения, управляющим персистентностью бина, свойствами транзакций и системой защиты данных. Теперь, когда наш Shop.ejbml готов, мы можем сгенерировать и скомпилировать классы контейнера. Для этого нам нужно запустить установленное в HomeBase средство выполнения. Это делается следующим образом: java com.ejbhome.Deployer .\conf\Shop.ejbml Приведенный ниже пример показывает, как будет выглядеть консоль нашего экрана, когда мы будем компилировать и разворачивать наши файлы. Наши команды выделены жирным шрифтом. E:\>javac cup\chap8\Shop\Books\*.java Теперь с помощью этой команды вы можете запустить сервер: java com.ejbhome.Server Напишите клиентский код В примере, приведенном ниже, предлагается образец клиентского кода для entity-бина. Клиент обычно работает самостоятельно и вносит в базу данных записи и обновляет цены. В начале клиент производит Naming.lookup()и находит ссылку на интерфейс BooksHome. Затем он создаёт набор экземпляров entity-бина и вносит соответствующие записи в базу данных. Кроме этого клиент выполняет различные методы нашего ShopBean, типа поиска или установки цены или названия книги. В Примере 12 показано приложение BooksTest, которое является клиентом нашего entity-бина Books. package com.gopalan.Shop.Books; import java.rmi.*; import java.util.*;
public class BooksTest {
static final int NUMBOOKS = 4;
public static void main(String[] args) throws Exception {
BooksHome home = (BooksHome)Naming.lookup ("Books");
System.out.println ( "Naming.lookup successful..." );
if (home == null) {
System.out.println( "null BooksHome returned..." ); } String title = "Book"; String author= "Author"; Vector v = new Vector ();
for (int i = 0; i < BooksTest.NUMBOOKS; i++) {
System.out.println ("ISBN = " +(i+1) +
" Book = " +title+(i+1) + " Author = " +author+(i+1) + " Creating home.create..."); v.addElement (home.create ((i+1),title+(i+1), author+(i+1),100.00,10)); }
for (int i = 0; i < BooksTest.NUMBOOKS; i++) {
Books books= (Books) (v.elementAt (i)); books.setPrice (books.getPrice ()+1);
System.out.println ("Final Price of " + books.getTitle () +
" is "+ books.getPrice ()); }
System.out.println ("Books.setBooksPrice successful...");
for (int i = 0; i < BooksTest.NUMBOOKS; i++) {
Books books= (Books)(home.findByPrimaryKey (new BooksPK (i+1))); books.setPrice (books.getPrice ()+1);
System.out.println ("Final Price of " + books.getTitle () +
" is "+ books.getPrice ()); }
System.out.println ("Books.findByPrimaryKey successful...");
} } Пример 12: Клиентское приложение BooksTest нашего entity-бина Теперь скомпилируйте и запустите клиента. Клиент создаст четыре записи в базе данных. Когда мы будем обсуждать session-бины, Вы увидите, как смоделировать session-бин, чтобы он мог выступать клиентом нашего entity-бина. |
| Справка | Условия | |
| В начало | Логин | Комментарий к колонке | Поиск | Почта |