7.3. Session Facade Pattern

Now that you've seen the three entity beans in our enterprise application, it's time to present the Session Facade session bean, CustomerSession EJB. The CustomerSession EJB is an enhanced version of the session bean we presented in Chapter 6 (see Listing 6.20 on page 256). For a detailed explanation of the Session Facade Pattern (and why you'd want to use it), see “Session Facade Pattern” on page 250. As you examine the code for the session facade, you'll see how it provides the business logic for a consistent interface to the three entity beans.

Figure 7-5 contains a more detailed diagram of the Session Facade implementation, including the three entity beans. The remote client access to the entity beans is through the Session Facade only. We show the methods in the Session Facade that the remote client uses to fulfill the requirements of the web site. The CustomerSession EJB accesses the entity beans through local interfaces. We also show the multiplicity relationships among the entity beans.

Figure 7-5. Architectural Overview of the Session Facade CustomerSession EJB, Its Client, and the Underlying Entity Beans Customer EJB, Order EJB, and LineItem EJB


There are additional motivations for using the Session Facade Pattern here. Although we presented this pattern in the previous chapter, its role becomes much more pronounced in designs with multiple related entity beans.

Design Guideline

The Session Facade bean provides the interface to each of the entity beans, Customer EJB, Order EJB, and LineItem EJB. It also provides the business logic that controls the three entity beans. It fulfills the life cycle creation and subsequent destruction control to maintain the correct business relationship among the entity beans. Without the Session Facade, this business logic would become the responsibility of the remote client. Not only would the business logic be duplicated in all general clients and require multiple remote methods, but it would unnecessarily complicate the interface between the remote client and entity beans. This approach would also adversely affect performance.


Value Object Pattern Revisited

Suppose a remote client (either a web component, a stand-alone Java client, or even another Enterprise JavaBeans component) wants to create an order, create a customer, or get all of the orders in a system. How does the remote client communicate with the CustomerSession EJB? Recall that we used the Value Object Pattern to encapsulate customer data with CustomerVO. “Value Objects” on page 42 discusses both the convenience factor and the performance reasons for encapsulating data to communicate between remote clients and session beans. Listing 5.1 on page 143 lists the code for the customer value object, which we continue to use unchanged in this chapter. We'll also need LineItemVO and OrderVO value objects, too. Let's look at LineItemVO first.

LineItemVO

Listing 7.17 contains the source for the LineItemVO class LineItemVO.java. A line item represents the recording selected by the customer. We store the recording title and the number of copies of this recording selected by this customer. Class LineItemVO must implement interface Serializable, since we transmit it remotely.

Note that we implement method equals() for LineItemVO objects to compare recording titles. Recall that the Java collection classes rely on equals() to perform comparisons.

Listing 7.17. LineItemVO.java
// LineItemVO.java
import java.util.*;

public class LineItemVO implements java.io.Serializable {
  private String title;
  private int quantity;

  public LineItemVO(String title, int quantity)
  {
    setTitle(title);
    setQuantity(quantity);
  }

  // getters
  public String getTitle() { return title; }
  public int getQuantity() { return quantity; }

  // setters
  public void setTitle(String title) {
    this.title = title;
  }

  public void setQuantity(int quantity) {
    this.quantity = quantity;
  }

  public boolean equals(Object lineItem) {
    return (title.equals(
      ((LineItemVO)lineItem).getTitle()));
  }
}

OrderVO

Remote clients use object OrderVO to transmit and receive data for an order. The web client is responsible for collecting data that constitutes an order and encapsulating it into an OrderVO object. This allows the CustomerSession EJB to create the actual entity beans (and thus persist the information to permanent datastore). The OrderVO object contains not only information about a specific order that we store in an Order EJB, but it also has information relating to a particular customer and all of its line item data. The CustomerSession EJB uses the customer information to create an Order EJB (thus initializing the Order EJB's CMR customer field). It will also use the line item data to create the LineItem EJBs for the order.

Listing 7.18 contains the source for OrderVO.java.

Listing 7.18. OrderVO.java
// OrderVO.java
import java.util.*;

public class OrderVO implements java.io.Serializable
{
  private double totalAmount;
  private int orderStatus;
  private Calendar orderDate;
  private Calendar shipDate;
  private String customerName;
  private Collection lineItems;

  public OrderVO(double amount, int status,
      Calendar orderDate, Calendar shipDate,
      String name, Collection lineItems)
  {
    setTotalAmount(amount);
    setOrderStatus(status);
    setOrderDate(orderDate);
    setShipDate(shipDate);
    setCustomerName(name);
    setLineItems(lineItems);
  }

  // getters
  public double getTotalAmount() { return totalAmount; }
  public int getOrderStatus() { return orderStatus; }
  public Calendar getOrderDate() {
    return (Calendar)orderDate.clone();
  }
  public Calendar getShipDate() {
    return (Calendar)shipDate.clone();
  }
  public String getCustomerName() { return customerName; }
  public Collection getLineItems() { return lineItems; }

  // setters
  public void setTotalAmount(double amount) {
    totalAmount = amount;
  }
  public void setOrderStatus(int status) {
    orderStatus = status;
  }
  public void setOrderDate(Calendar d) {
    orderDate = (GregorianCalendar)new GregorianCalendar(
      d.get(Calendar.YEAR),
      d.get(Calendar.MONTH),
      d.get(Calendar.DATE)); }

  public void setShipDate(Calendar d) {
    shipDate = (GregorianCalendar)new GregorianCalendar(
      d.get(Calendar.YEAR),
      d.get(Calendar.MONTH),
      d.get(Calendar.DATE)); }

  public void setCustomerName(String name) {
    customerName = name;
  }

  public void setLineItems(Collection items) {
    lineItems = items;
  }
}

CustomerSession EJB

Now that we've specified how the remote client sends and receives information to the session facade bean, it's time to show you this workhorse in detail.

Home Interface

The CustomerSession EJB is a stateless session bean with a single create() method, as shown in Listing 7.19. (This file is unchanged from Listing 6.16 on page 252.)

Listing 7.19. CustomerSessionHome.java
// CustomerSessionHome.java
import java.io.Serializable;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface CustomerSessionHome extends EJBHome {
    CustomerSession create() throws RemoteException,
           CreateException;
}

Remote Interface

The remote interface contains the business methods that manipulate our three entity beans. Because we have added the Order EJB and LineItem EJB to our Customer EJB, we require additional business methods to create an order and build a collection of line items. Listing 7.20 contains the remote interface, CustomerSession.

Listing 7.20. CustomerSession.java
// CustomerSession.java
import javax.ejb.*;
import java.rmi.RemoteException;
import java.util.*;

public interface CustomerSession extends EJBObject {

   public int getTotalCustomers()
      throws RemoteException;

  public void createCustomer(CustomerVO customer)
      throws CreateException, FinderException,
      RemoteException;

  public void changePassword(String name, String password)
      throws CustomerIdentityException, CustomerException,
      FinderException, RemoteException;

  public void changeEmail(String name, String email)
      throws CustomerIdentityException, CustomerException,
      FinderException, RemoteException;

  public void identifyCustomer(String name,
      String password) throws CustomerIdentityException,
      FinderException, RemoteException;
  public boolean getOrdersPending(String name)
      throws CustomerIdentityException,
      FinderException, RemoteException;

  public Collection getOrders(String name)
      throws CustomerIdentityException,
      FinderException, RemoteException;

  public void createOrder(OrderVO order)
    throws CreateException, CustomerIdentityException,
    FinderException, RemoteException;

  public Collection buildItems(Collection items)
    throws RemoteException;

  public Collection getCustomers()
    throws FinderException, RemoteException;

  public void shipOrdersByDate(Calendar orderDate)
    throws FinderException, RemoteException;
}

Method getOrders() returns a collection of OrderVO objects belonging to a customer identified by name. Method createOrder() creates a new Order EJB using information provided in the OrderVO object argument. Method buildItems() takes the collection of RecordingVO objects produced by the client and returns a collection of LineItemVO objects (eliminating duplicate titles by incrementing the corresponding quantity for that title).

The shipOrdersByDate() method “ships” all orders in the system that have not yet been shipped and have an order date that is equal to or earlier than the Calendar argument.

Design Guideline

A use case is a description of how someone would use your system. If you build use case diagrams for your enterprise application, then the Session Facade's remote interface should contain all the methods that implement each use case.


Bean Implementation

Since CustomerSession EJB is a stateless session bean, the bulk of the code is the implementation of the business methods we defined in the remote interface. Some of the methods we presented in an earlier version from Chapter 6 (see Listing 6.20 on page 256). For example, the methods that deal solely with the Customer EJB are unchanged. These include createCustomer(), changePassword(), changeEmail(), identifyCustomer(), getOrdersPending(), and getCustomers(). New to this implementation are the business methods that manipulate the Order EJBs and LineItem EJBs. These include getOrders(), createOrder(), buildItems(), and shipOrdersByDate().

You'll also note that ejbCreate() initializes instance variables customerHome, orderHome, and lineItemHome. These hold the local home interfaces to the three entity beans. Since CustomerSession EJB is stateless, the container may use the same instance among multiple clients and share these (client-independent) instance variables.

A few methods deserve special mention here. Let's look at getOrders() first (see page 343.) Method getOrders() returns a collection of OrderVO objects for the customer named in the argument. We first access the customer local home interface and invoke customer finder method findByCustomerName(). This returns a CustomerLocal object (within the collection), which provides access to the business methods of the Customer EJB. We then access the Customer EJB business method getOrders(), which returns a collection of OrderLocal objects. This in turn provides access to the Order EJB business methods. (Customer EJB method getOrders() returns the CMR field orders.) The Order EJB contains relationship access method getLineItems(), which returns a collection of LineItemLocal objects. We now begin to build the OrderVO object to transmit back to the client.

Since an OrderVO object contains a collection of LineItemVO objects, we build these first. We then extricate the details of the Order EJB to put into the OrderVO object. Note that we convert the date from a long to a Calendar object as part of this process.

CMP Limitation

In the EJB 2.0 specification, the EJB Query Language does not currently support SQL date objects. Therefore, we store Calendar objects by converting them to long data types using Calendar.getTime() (which returns a Date) and Date.getTime() (which returns a long), as shown below. To convert a long to a Calendar object, we create a Date object with a long and call Calendar's setTime() with a Date object.


// convert Calendar object to long
long dateAsLong =
      myCalendarObject.getTime().getTime();

// convert long to Calendar object
Calendar myCalendarObject =
      new GregorianCalendar();
myCalendarObject.setTime(new Date(dateAsLong));

Each OrderVO object that we build contains information from the Order EJB, as well as information from the related Customer EJB and the LineItem EJBs.

The second method that deserves special attention is createOrder() (see page 346). Here we show you how to construct an Order EJB, as well as how to set its relationship fields. We pass an OrderVO object to createOrder() and extract the customer name. We can then identify the Customer EJB using finder method findByCustomerName().

After successfully finding the relevant Customer EJB, we create a new Order EJB using the OrderLocalHome's create() method. We include the CustomerLocal object (cust) with the arguments to the Order's create() call. We then build the LineItem EJBs using the LineItemLocalHome object and invoke the create() method. As we build the LineItem EJBs, we associate each LineItem EJB with the newly created OrderEJB by including OrderLocal object myorder with the LineItem EJB create() call.

Design Guideline

Even though we implement two-way navigation with all our entity bean relationships, the entity bean create process must only initialize one end of the relationship. The container initializes the other end for you during the current transaction context. The container's involvement here guarantees the referential integrity of CMR fields.


Finally, look at method shipOrdersByDate() (see page 344). We provide a Calendar object as a target date, requesting all orders that have not yet been shipped with an order date that is equal to or earlier than the target date. This method uses a custom finder to obtain a collection of OrderLocal objects. After acquiring the collection, we can invoke business method shipOrder() in Order EJB for each order.

Listing 7.21 shows the bean implementation code in file CustomerSessionBean.java.

Listing 7.21. CustomerSessionBean.java
// CustomerSessionBean.java
import java.rmi.RemoteException;
import javax.ejb.*;
import javax.naming.*;
import java.util.*;

public class CustomerSessionBean implements SessionBean {

  // initialize in ejbCreate()

  private CustomerLocalHome customerHome;
  private OrderLocalHome orderHome;
  private LineItemLocalHome lineItemHome;

  // Business methods

  // Return the number of Customers in the database

   public int getTotalCustomers() throws FinderException {
    return customerHome.getTotalCustomers();
  }
  // Create a new Customer in the CustomerDB
  // verify that the name is unique and the password
  // is non-empty.

  public void createCustomer(CustomerVO customer)
      throws CreateException, FinderException {
    if (customer.getName() == null
        || customer.getPassword() == null
        || customer.getEmail() == null) {
      throw new CreateException("Customer data is null");
    }

    if (customer.getName().equals("")
        || customer.getPassword().equals("")
        || customer.getEmail().equals("")) {
      throw new CreateException(
            "Customer fields cannot be empty.");
    }

    Collection c =
      customerHome.findByCustomerName(customer.getName());
    if (c.size() == 0) {
      customerHome.create(
        customer.getName(),
        customer.getPassword(),
        customer.getEmail());
    }

    else {
      throw new CreateException(
          "Customer name already in use.");
    }
  }

  // Change the password for the customer.
  // Make sure customer is in the database
  // Throws CustomerIdentityException if no match.
  // Throws CustomerException if other problems.
  public void changePassword(String name, String password)
      throws CustomerIdentityException, CustomerException,
      FinderException {
    if (password.equals("")) {
      throw new CustomerException(
          "Password cannot be empty");
    }

    Collection c = customerHome.findByCustomerName(name);
    if (c.size() == 1) {
      Iterator i=c.iterator();
      CustomerLocal cust = (CustomerLocal)i.next();
      cust.setPassword(password);
    }
    else {
      throw new CustomerIdentityException(
            "Cannot find customer " + name);
    }
  }

  // Change the email for the customer.
  // Make sure customer is in the database
  // Throws CustomerIdentityException if no match.
  // Throws CustomerException if other problems.

  public void changeEmail(String name, String email)
      throws CustomerIdentityException, CustomerException,
      FinderException {
    if (email.equals("")) {
      throw new CustomerException(
          "Email cannot be empty");
    }

    Collection c = customerHome.findByCustomerName(name);
    if (c.size() == 1) {
      Iterator i=c.iterator();
      CustomerLocal cust = (CustomerLocal)i.next();
      cust.setEmail(email);
    }
    else {
      throw new CustomerIdentityException(
            "Cannot find customer " + name);
    }
  }

  // Given a customer name, make sure the password
  // matches the customer's name in the database
  // Throws CustomerIdentityException if no match.

  public void identifyCustomer(String name,
        String password) throws CustomerIdentityException,
        FinderException {
    Collection c = customerHome.findByCustomerName(name);
    if (c.size() == 1) {
      Iterator i=c.iterator();
      CustomerLocal cust = (CustomerLocal)i.next();
      if (!cust.getPassword().equals(password)) {
        throw new CustomerIdentityException(
            "Incorrect Password for customer " + name);
      }
    }
    else {
      throw new CustomerIdentityException(
            "Cannot find customer " + name);
    }
  }

  // Given the customer name,
  // get the OrdersPending flag

  public boolean getOrdersPending(String name)
      throws CustomerIdentityException, FinderException {
    Collection c = customerHome.findByCustomerName(name);
    if (c.size() == 1) {
      Iterator i=c.iterator();
      CustomerLocal cust = (CustomerLocal)i.next();
      return cust.getOrdersPending();
    }
    else {
      throw new CustomerIdentityException(
            "Cannot find customer " + name);
    }
  }

  // Given the customer name,
  // return ArrayList of OrderVOs
  // for that customer

  public Collection getOrders(String name)
      throws CustomerIdentityException, FinderException {

    Collection c = customerHome.findByCustomerName(name);

    if (c.size() == 1) {
      Iterator i=c.iterator();
      CustomerLocal cust = (CustomerLocal)i.next();

      // create an ArrayList of OrderVOs
      ArrayList orderList = new ArrayList();

      Collection a = cust.getOrders();
      i = a.iterator();

      while (i.hasNext()) {
        OrderLocal orderEJB = (OrderLocal)i.next();

        // get orderEJB's ArrayList of LineItem EJBs
        // and put them in a new ArrayList of LineItemVOs

        ArrayList lineItems = new ArrayList();
        Iterator lineIt =
                   orderEJB.getLineItems().iterator();
        while (lineIt.hasNext()) {
          LineItemLocal item =
                   (LineItemLocal) lineIt.next();
          lineItems.add(new LineItemVO(
                   item.getTitle(), item.getQuantity()));
        }
        // convert OrderEJB longs to Calendar objects
        Calendar orderDate = new GregorianCalendar();
        orderDate.setTime(new Date(
                 orderEJB.getOrderDate()));
        Calendar shipDate = new GregorianCalendar();
        shipDate.setTime(new Date(
                 orderEJB.getShipDate()));

        // create OrderVO object and add to orderlist
        OrderVO order =
          new OrderVO(orderEJB.getTotalAmount(),
            orderEJB.getOrderStatus(),
            orderDate,
            shipDate,
            cust.getName(),
            lineItems);
        orderList.add(order);
      }
      return orderList;
    }

    else {
      throw new CustomerIdentityException(
            "Cannot find customer " + name);
    }
  }

  // Ship all Order EJBs with an orderDate that
  // is equal to or earlier than argument orderDate

  public void shipOrdersByDate(Calendar orderDate)
      throws FinderException {
    // convert Calendar object to long
    long when = orderDate.getTime().getTime();

    // use finder to get orders
    try {
    Collection orders =
      orderHome.findByOrderDatePrevious(when,
        OrderLocalHome.InProcess);

    Iterator i = orders.iterator();
    // use today's date for the ship date
    Date now = new Date();
    while (i.hasNext()) {
      OrderLocal orderEJB = (OrderLocal)i.next();
      orderEJB.shipOrder(now.getTime());
      System.out.println("Shipped order for " +
          orderEJB.getCustomer().getName());
    }

    } catch (Exception ex) {
      ex.printStackTrace();
      throw new EJBException(
          "shipOrdersByDate: " + ex.getMessage());
    }
  }

  // Get the shoppingList of RecordingVOs and build
  // an ArrayList of LineItemVOs with no duplicates.
  // Increment the quantity when we find duplicates.

  public Collection buildItems(Collection items) {
    try {
      ArrayList itemList = new ArrayList();
      Iterator i = items.iterator();

      while (i.hasNext()) {
        RecordingVO r = (RecordingVO) i.next();
        LineItemVO thisItem =
                 new LineItemVO(r.getTitle(), 1);
        // is LineItemVO already in itemList?
        int index = itemList.indexOf(thisItem);

        if (index < 0) {
          // not a duplicate;
          // just add this one
          itemList.add(thisItem);
        }

        else {
          // Duplicate LineItemVO--
          // Get the duplicate & increment quantity
          LineItemVO l = (LineItemVO) itemList.get(index);
          int q = l.getQuantity() + 1;
          l.setQuantity(q);

          // Replace with updated quantity field
          itemList.set(index, l);
        }
      }
      return itemList;

    } catch (Exception ex) {
      ex.printStackTrace();
      throw new EJBException(
          "buildItems: " + ex.getMessage());
    }
  }

  public void createOrder(OrderVO order)
      throws CustomerIdentityException, CreateException,
      FinderException {

    Collection c = customerHome.findByCustomerName(
          order.getCustomerName());
    if (c.size() == 1) {
      // get CustomerEJB
      Iterator i = c.iterator();
      CustomerLocal cust = (CustomerLocal)i.next();

      try {
        // get the LineItemVO ArrayList
        Collection items = order.getLineItems();
        if (items.isEmpty()) {
          throw new CreateException(
              "createOrder: LineItems cannot be empty.");
        }

        // create Order EJB
        // include Customer EJB with create arguments
        OrderLocal myorder = orderHome.create(
          order.getTotalAmount(),
          order.getOrderStatus(),
            // convert Calendar objects to longs
          order.getOrderDate().getTime().getTime(),
          order.getShipDate().getTime().getTime(),
          cust);

        // create LineItem EJBs
        // include Order EJB with create arguments
        Iterator lineIt = items.iterator();
        while (lineIt.hasNext()) {
          LineItemVO lineItem =
                (LineItemVO) lineIt.next();
          LineItemLocal myLineItem = lineItemHome.create(
            lineItem.getTitle(),
            lineItem.getQuantity(),
            myorder);
        }

        cust.setOrdersPending(true);
      }

      catch (Exception ex) {
        System.out.println(ex.getMessage());
        ex.printStackTrace();
        throw new EJBException(
            "CustomerSessionBean: createOrder");
      }
    }

    else {
      throw new CustomerIdentityException(
            "Cannot find customer " +
            order.getCustomerName());
    }
  }

  // Get all the customers in the customer database
  // Return an ArrayList of CustomerVOs

  public Collection getCustomers()
                   throws FinderException {

    // return an ArrayList of CustomerVOs
    ArrayList customerList = new ArrayList();
    Collection a = customerHome.findAll();
    Iterator i = a.iterator();

    while (i.hasNext()) {
      CustomerLocal customerEJB = (CustomerLocal)i.next();

      CustomerVO customer =
        new CustomerVO(customerEJB.getName(),
          customerEJB.getPassword(),
          customerEJB.getEmail());
      customerList.add(customer);
    }

    return customerList;
  }

   // EJB Methods
  public CustomerSessionBean() {}

  public void ejbCreate() {
    try {
      Context initial = new InitialContext();
      System.out.println("CustomerSession ejbCreate()");

      // Find LocalHome Interface to CustomerEJB
      Object objref =
            initial.lookup("java:comp/env/ejb/Customer");
      customerHome = (CustomerLocalHome)objref;

      // Find LocalHome Interface to OrderEJB
      objref = initial.lookup("java:comp/env/ejb/Order");
      orderHome = (OrderLocalHome)objref;

      // Find LocalHome Interface to LineItemEJB
      objref =
             initial.lookup("java:comp/env/ejb/LineItem");
      lineItemHome = (LineItemLocalHome)objref;
    } catch (Exception ex) {
      ex.printStackTrace();
      throw new EJBException(ex.getMessage());
    }
    System.out.println("CustomerSessionBean: ejbCreate");
  }
   public void ejbRemove() {}
   public void ejbActivate() {}
   public void ejbPassivate() {}
   public void setSessionContext(SessionContext sc) {}

} // CustomerSessionBean

Deployment Descriptor

Listing 7.22 shows portions of the deployment descriptor for the EJB JAR file containing the CustomerSession EJB. The CustomerSession EJB is a stateless session bean with container-managed transactions. It has remote (CustomerSession) and remote home (CustomerSessionHome) interfaces and references the Customer, Order, and LineItem entity beans through their local and local home interfaces. Under the <assembly-descriptor> tag, the deployment descriptor lists all of its transactional methods, along with the transaction attribute we assign (in all cases, attribute Required). The <method> tag identifies methods with transactions. We show the <method> tags for createCustomer() and createOrder() only. We highlight the tag values for readability.

Listing 7.22. Generated XML Tags for CustomerSession EJB
. . .
<session>
 <display-name>CustomerSessionBean</display-name>
     <ejb-name>CustomerSessionBean</ejb-name>
     <home>CustomerSessionHome</home>
     <remote>CustomerSession</remote>
     <ejb-class>CustomerSessionBean</ejb-class>
     <session-type>Stateless</session-type>
     <transaction-type>Container</transaction-type>

     <ejb-local-ref>
       <ejb-ref-name>ejb/Customer</ejb-ref-name>
       <ejb-ref-type>Entity</ejb-ref-type>
       <local-home>CustomerLocalHome</local-home>
       <local>CustomerLocal</local>
       <ejb-link>CustomerBean</ejb-link>
     </ejb-local-ref>
     <ejb-local-ref>
       <ejb-ref-name>ejb/Order</ejb-ref-name>
       <ejb-ref-type>Entity</ejb-ref-type>
       <local-home>OrderLocalHome</local-home>
       <local>OrderLocal</local>
       <ejb-link>OrderBean</ejb-link>
     </ejb-local-ref>

     <ejb-local-ref>
       <ejb-ref-name>ejb/LineItem</ejb-ref-name>
       <ejb-ref-type>Entity</ejb-ref-type>
       <local-home>LineItemLocalHome</local-home>
       <local>LineItemLocal</local>
       <ejb-link>LineItemBean</ejb-link>
     </ejb-local-ref>

     <security-identity>
       <description></description>
       <use-caller-identity></use-caller-identity>
     </security-identity>
   </session>
</enterprise-beans>

<assembly-descriptor>
   <container-transaction>
     <method>
       <ejb-name>CustomerSessionBean</ejb-name>
       <method-intf>Remote</method-intf>
       <method-name>createCustomer</method-name>
       <method-params>
         <method-param>CustomerVO</method-param>
       </method-params>
     </method>
     <trans-attribute>Required</trans-attribute>
   </container-transaction>

<container-transaction>
     <method>
       <ejb-name>CustomerSessionBean</ejb-name>
       <method-intf>Remote</method-intf>
       <method-name>createOrder</method-name>
        <method-params>
          <method-param>OrderVO</method-param>
        </method-params>
      </method>
      <trans-attribute>Required</trans-attribute>
    </container-transaction>
    . . .
 </assembly-descriptor>
</ejb-jar>

Entity Beans and Session Beans Revisited

The three entity beans that we described and coded reflect business data. While we can add custom finders or business methods to these entity beans, we expect the underlying database to be stable and for the entity beans to be highly reusable components.

In contrast, as we add requirements or use cases to our system, our CustomerSession bean may expand. Or, we may implement a second session facade to handle a different set of use cases. Thus, a flexible, scalable system should have a stable backbone entity bean structure upon which we can build use cases within a session facade. Adding custom finder methods or business methods to the entity bean does not affect the underlying entity bean or database structure.

This approach again points to the efficiency and flexibility of the Session Facade Pattern and its importance in a well-designed enterprise system.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.40.189