5.1. Introducing Stateful Session Beans

A stateful session bean keeps track of client-specific data over the course of a session. The client-related data is stored in instance variables of the stateful session bean. The lifetime of the bean corresponds to one client's session and its state reflects the work performed throughout the session. The session bean keeps track of the conversational state between the client and the bean. Throughout its lifetime, the EJB container assigns an instance of a stateful session bean to a single client. The state of any given instance is dependent on how the client creates the bean and the invocation of its business methods. When the session terminates, the bean's state is released and the bean's instance no longer exists.

Stateful Session Passivation and Activation

In a J2EE environment, a running application uses many system resources. The EJB container, which controls the life cycle and activation state of its enterprise beans, may need to reacquire resources used by a stateful session bean. These resources include system memory, socket connections, and database connections. When resources must be reclaimed, the container serializes a bean's state and copies it to secondary storage. This process is called passivation. When it's time to restore a bean to its active state, the container reads the bean's state from secondary storage and de-serializes the objects. This process is called activation. In general, the EJB container performs this work quietly and transparently.

It's not always possible for the EJB container to serialize all state information in a session bean. If an instance variable, for example, does not implement the Serializable interface, the container cannot save and restore the data. In this case (and in other scenarios which might require special attention), the bean developer provides code to reinitialize the bean properly.

The session bean interface provides the ejbPassivate() and ejbActivate() methods, which allow bean developers to control the passivation and activation tasks for a session bean. The container invokes ejbPassivate() just before it passivates the instance and ejbActivate() just after it activates the instance. The bean developer places the code for these methods in the session bean implementation class.

Let's look at an example. Suppose a stateful session bean contains an instance variable (ds) which is a reference to a DataSource object. To properly passivate this instance, we must assign null to the ds reference in ejbPassivate(), since a reference to an object cannot be serialized. To activate the instance, we provide the code to reinitialize the ds reference in ejbActivate(). The following code snippets show how to do this.

// example ejbPassivate() inside bean implementation class
public void ejbPassivate() {
  // DataSource ds is an instance variable
  ds = null;
}

// example ejbActivate() inside bean implementation class
public void ejbActivate() {
    String dbName = "java:comp/env/jdbc/MusicDB";
    try {
      InitialContext ic = new InitialContext();
      // DataSource ds is an instance variable
      ds = (DataSource) ic.lookup(dbName);
    } catch (Exception ex) {
      throw new EJBException("Cannot find DataSource: " +
        ex.getMessage());
    }
}

Design Guideline

In general, you should design an ejbPassivate() method to “undo” (or release) any actions (or resources) performed (or acquired) by the ejbActivate() method. For example, close a database connection in ejbPassivate() if you acquire it in ejbActivate().


The astute reader will recognize part of this code from our Music EJB session bean in Chapter 4, specifically the ejbCreate() method found in the MusicBean implementation class (see its source on page 100). Why didn't we need ejbPassivate() and ejbActivate() methods for the Music EJB session bean? Recall that Music EJB is a stateless session bean. The EJB container never needs to passivate it. Once a client returns from a method invocation, the container may assign the instance to another client. This sharing means that expensive resources are more easily distributed among various clients. Furthermore, if the container needs to recover resources, it simply destroys the instance. There is no “conversational state” to save. Thus, there is no need to save and restore state through passivation and activation.

Design Guideline

When you're choosing between a stateful or stateless session bean to implement a business process, it helps to understand how the EJB container manages different session beans. A knowledge of each bean's life cycle is one way to gauge the performance impact to your enterprise application.


How does the EJB container decide which stateful bean to passivate? Usually, a container uses heuristics based on how recently a client has accessed a bean (typically the container will passivate the bean that has been called the least recently). Furthermore, if the bean is in the middle of a method call or involved in a transaction, the container cannot passivate it. (A transaction defines the boundaries of uninterruptible database operations. We discuss transactions in Chapter 6.)

This chapter will demonstrate two stateful session beans by building on previous designs from earlier chapters. Our first example, a MusicCart EJB, implements the (now traditional) online shopping paradigm. A client creates a shopping cart of music recordings, adds or removes recordings from the cart, and displays the cart's contents.

Our second stateful session bean implements the Value List Iterator Pattern. This pattern is extremely useful for managing large lists of data. We'll modify our stateless session Music EJB slightly and reuse the MusicDAO from the previous chapter to access the Music Collection database. You will see that our implementation takes advantage of the performance differences between stateful and stateless session beans, leveraging the different benefits of each one to fit our application.

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

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