Пример cart представляет корзину покупок в книжном онлайн-магазине и использует сессионный компонент с состоянием для управления операциями с корзиной покупок. Клиент бина может добавить книгу в корзину, удалить книгу или получить содержимое корзины. Для сборки cart вам понадобится следующий код:
Все сессионные компоненты имеют соответствующий им класс Java. Все Enterprise-бины, которые разрешают удалённый доступ, должны иметь удалённый бизнес-интерфейс. Для удовлетворения потребностей конкретного приложения Enterprise-бину также могут потребоваться некоторые вспомогательные классы. Сессионный компонент CartBean использует два вспомогательных класса — BookException и IdVerifier, которые обсуждаются в разделе Вспомогательные классы.
Исходный код для этого примера находится в каталоге tut-install/examples/ejb/cart/.
Бизнес-интерфейс
Бизнес-интерфейс Cart — это интерфейс Java, который определяет все бизнес-методы, реализованные в классе компонента. Если класс бина реализует один интерфейс, этот интерфейс считается бизнес-интерфейсом. Бизнес-интерфейс является локальным интерфейсом, если он не помечен аннотацией javax.ejb.Remote. Аннотация javax.ejb.Local в этом случае необязательна.
Класс бина может реализовывать более одного интерфейса. В этом случае бизнес-интерфейсы должны быть либо явно аннотированы @Local или @Remote, либо указаны путём аннотирования класса компонента аннотациями @Local или @Remote. Однако следующие интерфейсы исключаются при определении того, реализует ли класс бина более одного интерфейса:
Исходный код бизнес-интерфейса Cart выглядит следующим образом:
package javaeetutorial.cart.ejb;
import cart.util.BookException;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface Cart {
public void initialize(String person) throws BookException;
public void initialize(String person, String id) throws BookException;
public void addBook(String title);
public void removeBook(String title) throws BookException;
public List<String> getContents();
public void remove();
}
Класс сессионного бина
Класс сессионного компонента для этого примера называется CartBean. Как и любой сессионный компонент с состоянием, класс CartBean должен соответствовать следующим требованиям.
Сессионные компоненты с сохранением состояния могут также выполнять следующие действия.
-
Реализовать бизнес-интерфейс — интерфейс Java Реализовать бизнес-интерфейс — хорошая практика.
-
Реализовать любые дополнительные Callback-методы жизненного цикла, аннотированные @PostConstruct, @PreDestroy, @PostActivateи @PrePassivate.
-
Реализовать любые необязательные бизнес-методы, аннотированные @Remove.
Исходный код для класса CartBean выглядит следующим образом:
package javaeetutorial.cart.ejb;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javaeetutorial.cart.util.BookException;
import javaeetutorial.cart.util.IdVerifier;
import javax.ejb.Remove;
import javax.ejb.Stateful;
@Stateful
public class CartBean implements Cart {
String customerId;
String customerName;
List<String> contents;
@Override
public void initialize(String person) throws BookException {
if (person == null) {
throw new BookException("Null person not allowed.");
} else {
customerName = person;
}
customerId = "0";
contents = new ArrayList<>();
}
@Override
public void initialize(String person, String id)
throws BookException {
if (person == null) {
throw new BookException("Null person not allowed.");
} else {
customerName = person;
}
IdVerifier idChecker = new IdVerifier();
if (idChecker.validate(id)) {
customerId = id;
} else {
throw new BookException("Invalid id: " + id);
}
contents = new ArrayList<>();
}
@Override
public void addBook(String title) {
contents.add(title);
}
@Override
public void removeBook(String title) throws BookException {
boolean result = contents.remove(title);
if (result == false) {
throw new BookException("\"" + title + " not in cart.");
}
}
@Override
public List<String> getContents() {
return contents;
}
@Remove
@Override
public void remove() {
contents = null;
}
}
Callback-методы жизненного цикла
Метод в классе бина может быть объявлен как Callback-метод жизненного цикла, добавлением в метод следующих аннотаций.
-
javax.annotation.PostConstruct: методы, аннотированные с помощью @PostConstruct, вызываются контейнером для вновь созданных объектов бинов после завершения инъецирования всех зависимостей и до вызова первого бизнес-метода в Enterprise-бине.
-
javax.annotation.PreDestroy: методы, аннотированные с помощью @PreDestroy, вызываются после завершения любого аннотированного @Remove метода и перед удалением Enterprise-бина контейнером.
-
javax.ejb.PostActivate: методы, помеченные @PostActivate, вызываются контейнером после того, как контейнер перемещает компонент из вторичного хранилища в активное состояние.
-
javax.ejb.PrePassivate: методы, аннотированные @PrePassivate, вызываются контейнером до его пеактивации Enterprise-бином, то есть контейнер временно удаляет бин из среды и сохраняет его во вторичное хранилище.
Callback-методы жизненного цикла должны возвращать void и не иметь параметров.
Бизнес-методы
Основная цель сессионного компонента — запуск бизнес-задач для клиента. Клиент вызывает бизнес-методы для ссылки на объект, который он получает при инъецирования зависимости или поиске JNDI. С точки зрения клиента, бизнес-методы работают локально, хотя они выполняются удалённо в сессионном компоненте. В следующем фрагменте кода показано, как программа CartClient вызывает бизнес-методы:
cart.initialize("Duke DeEarl", "123");
...
cart.addBook("Bel Canto");
...
List<String> bookList = cart.getContents();
...
cart.removeBook("Gravity's Rainbow");
Класс CartBean реализует бизнес-методы в следующем коде:
@Override
public void addBook(String title) {
contents.add(title);
}
@Override
public void removeBook(String title) throws BookException {
boolean result = contents.remove(title);
if (result == false) {
throw new BookException("\"" + title + "not in cart.");
}
}
@Override
public List<String> getContents() {
return contents;
}
Сигнатура бизнес-метода должна соответствовать следующим правилам.
-
Имя метода не должно начинаться с ejb, чтобы избежать конфликтов с Callback-методами, определёнными архитектурой EJB. Например, вы не можете вызвать бизнес-метод ejbCreate или ejbActivate.
-
Модификатор доступа должен быть public.
-
Если бин разрешает удалённый доступ через удалённый бизнес-интерфейс, аргументы и возвращаемые типы должны быть допустимыми типами для API удалённого вызова методов Java (RMI).
-
Если бин является конечной точкой веб-сервиса JAX-WS, аргументы и возвращаемые типы для аннотированных методов @WebMethod должны быть допустимыми типами для JAX-WS.
-
Если бин является ресурсом JAX-RS, аргументы и возвращаемые типы для методов ресурса должны быть допустимыми типами для JAX-RS.
-
Модификатор не должен быть static или final.
Предложение throws может содержать исключения, которые вы определяете для своего приложения. Например, метод removeBook выдает BookException, если книга отсутствует в корзине.
Чтобы указать на проблему на уровне системы, например невозможность подключения к базе данных, бизнес-метод может выбросить javax.ejb.EJBException. Контейнер не будет обёртывать (wrap) исключения приложения, такие как BookException. Поскольку EJBException является дочерним классом RuntimeException, вам не нужно добавлять его в throws бизнес-метода.
Метод @Remove
Бизнес-методы, аннотированные javax.ejb.Remove в классе сессионного компонента с сохранением состояния, могут вызываться клиентами Enterprise-бина для удаления объекта компонента. Контейнер удалит Enterprise-бин после завершения метода @Remove независимо от того, завершился он нормально или с ошибкой.
В CartBean метод remove помечен аннотацией @Remove:
@Remove
@Override
public void remove() {
contents = null;
}
Вспомогательные классы
Сессионный компонент CartBean имеет два вспомогательных класса: BookException и IdVerifier. BookException выбрасывается методом removeBook, а IdVerifier валидирует customerId в одном из методов create. Вспомогательные классы могут находиться в файле EJB JAR, который содержит класс Enterprise-бина. Или в WAR-файле, если Enterprise-бин упакован в WAR. Или EAR-файле, содержащем файл EJB JAR, WAR-файл или отдельный JAR-файл библиотеки. В cart вспомогательные классы включены в библиотечный JAR, используемый клиентским приложением, и EJB JAR.
Запуск cart
Теперь вы готовы скомпилировать удалённый интерфейс (Cart.java), класс Enterprise-бина (CartBean.java), клиентский класс (CartClient.java) и вспомогательные классы (BookException.java и IdVerifier.java).
Вы можете использовать IDE NetBeans или Maven для сборки, упаковки, развёртывания и запуска приложения cart.
Здесь рассматриваются следующие темы:
Запуск cart с IDE NetBeans
-
Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).
-
В меню «Файл» выберите «Открыть проект».
-
В диалоговом окне «Открыть проект» перейдите к:
-
Выберите каталог cart.
-
Установите флажок Открыть требуемые проекты.
-
Нажмите Открыть проект.
-
На вкладке «Проекты» кликните правой кнопкой мыши проект cart и выберите «Сборка».
Это создаёт и упаковывает приложение в cart.ear, расположенный в tut-install/examples/ejb/cart/cart-ear/target/, и развёртывает этот файл EAR в ваш объект GlassFish Server.
Вы увидите выходные данные приложения-клиента cart-app-client на вкладке Вывод:
...
Retrieving book title from cart: Infinite Jest
Retrieving book title from cart: Bel Canto
Retrieving book title from cart: Kafka on the Shore
Removing "Gravity's Rainbow" from cart.
Caught a BookException: "Gravity's Rainbow" not in cart.
Запуск cart с помощью Maven
-
Удостоверьтесь, чтобы GlassFish Server был запущен (см. Запуск и остановка сервера GlassFish).
-
В окне терминала перейдите в:
tut-install/examples/ejb/cart/
-
Введите следующую команду:
Эта команда компилирует и упаковывает приложение в файл EAR, cart.ear, расположенный в каталоге target, и развёртывает EAR в GlassFish Server.
Затем клиентские заглушки извлекаются и запускаются. Это эквивалентно выполнению следующей команды:
appclient -client cart-ear/target/cart-earClient.jar
Клиентский JAR cart-earClient.jar содержит клиентский класс приложения, вспомогательный класс BookException и бизнес-интерфейс Cart.
При запуске клиента контейнер клиентского приложения инъецирует все ссылки на компоненты, объявленные в классе клиентского приложения, в данном случае ссылку на Enterprise-бин Cart.
В окне терминала вы увидите вывод cart-app-client:
...
Retrieving book title from cart: Infinite Jest
Retrieving book title from cart: Bel Canto
Retrieving book title from cart: Kafka on the Shore
Removing "Gravity's Rainbow" from cart.
Caught a BookException: "Gravity's Rainbow" not in cart.