Группа аксессоров и объекты значения


С точки зрения дизайна, было сделано то, что мы ввели сессионный компонент ShowMahager, являющийся простым façade (фасадом), который могут использовать клиенты для создания, удаления фильмов в системе, за которым располагаются наши entity bean'ы. Ясно, что сессионный компонент ShowManager предназначен для управления системой JavaTheater - предполагается, что обычные пользователи не будут изменять списочную информацию.

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

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

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

package javatheater.valueobject;

//:example09/src/ejb-tier/javatheater/valueobject/MovieItem.java
/**
* MovieItem является объектом данных, используемый для передачи
* структурированной информации о Movie между клиентом и ejb.
*/
public class MovieItem implements java.io.Serializable {
  
public Integer pk;
  
public String title;
  
  
public MovieItem(Integer pk, String title) {
     
this.pk = pk;
     
this.title = title;
  
}
}
// /:~

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

//:example10/src/ejb-tier/javatheater/ejb/implementation/MovieBean.java
package javatheater.ejb.implementation;

import javax.ejb.*;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

/**
* Этот код реализации сущностного компонента
<code>Movie</code>.
*
*
@see javatheater.ejb.MovieHome
* @ejb:bean name="Movie" local-jndi-name="javatheater/Movie" view-type="local"
*           type="CMP" primkey-field="id" reentrant="False"
* @ejb:pk class="java.lang.Integer"
* @ejb:home local-class="javatheater.ejb.MovieHome"
* @ejb:interface local-class="javatheater.ejb.Movie"
* @ejb:finder signature="java.util.Collection findByTitle(java.lang.String
*             title)" query="SELECT OBJECT(m) FROM Movie m WHERE m.title=?1"
* @ejb:finder signature="java.util.Collection findAll()" query="SELECT
*             OBJECT(m) FROM Movie m"
* @ejb:env-entry name="CounterName" value="MoviePKCounter"
*                type="java.lang.String"
*/
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) {
   }
  
  
/**
    * Домашний метод возвращает имя счетчика (String) для генерации уникального
    * значения первичного ключа фильма. Реальное имя определяется как
    * переменная окружения компонента Movie.
    *
    * @ejb:home-method
    */
  
public String ejbHomeGetCounterName() {
     
try {
        
Context initial = new InitialContext();
        
return (String) initial.lookup("java:comp/env/CounterName");
     
}
     
catch (NamingException e) {
        
throw new EJBException(e);
     
}
   }
  
  
/**
    * Возвращает Movie id, который также является первичным ключем.
    *
    * @ejb:pk-field
    * @ejb:persistent-field
    * @ejb:interface-method
    */
  
abstract public Integer getId();
  
  
/**
    * Этот метод не является частью удаленного интерфейса но ejbdoclet будет
    * все равно генерировать его реализацию. Этот методы вызывается из
    * ejbCreate().
    */
  
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'а, это просто обычный сессионный компонент без состояний с удаленным клиентским представлением. Метод ejbCreate( ) не делает ничего специального, за исключением получения домашнего интерфейса entity компонента Movie, который будет использоваться позже в методе getMovie(…). getMovie(…) реализуется для: получения экземпляра Movie по значению первичного ключа, который передан в качестве аргумента; создания объекта MovieItem, заполняющегося информацией о фильме; и возвращения объекта MovieItem.

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

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

Поисковые методы и EJB-QL

Взаимосвязь компонентов

Заключение