Section 6.6. Session Bean Specifics


6.6. Session Bean Specifics

Now that we've seen all the basic elements of implementing, deploying, and using an EJB, let's look a bit at the specifics of implementing session beans.

Beans that simply provide a set of well-defined functionality to clients are best-suited to be session beans. A simplified view of session beans is to think of them as regular remotely callable objects (like RMI objects) that are managed by an EJB container and therefore have access to all the basic EJB services (such as lifecycle management and security). Another way to decide whether an EJB should be a session bean is to remember what a session bean isn't: session beans are not meant to represent persistent data entities. A client acquires a reference to a session bean and asks it to perform functional services by calling methods on the bean. If the chunk of functionality you want to package for clients fits this description, the session bean model is probably the right one.

A session bean gets its name from the fact that it doesn't live beyond the lifetime of its serverin other words, it is not persistent. If an EJB client has a reference to a session bean and the host EJB server restarts, that session bean reference is no longer valid. You can reacquire a session bean of the same type from the same server after the restart, but it's not guaranteed to be in the same state as the bean you had before the server restart.

In terms of implementing session beans, the following sections cover specific requirements for session beans in addition to the general EJB requirements spelled out earlier.

6.6.1. Session Bean Implementation Classes

Session bean implementation classes must follow these rules:

  • Session bean classes must implement the javax.ejb.SessionBean interface.

  • The implementation class also must implement the setSessionContext( ) method specified in the SessionBean interface. The container calls this method on the session bean just after the bean has been created, passing in a javax.ejb.SessionContext object that represents the runtime context for the bean. This session context is valid for the life of the bean.

6.6.2. Stateless Versus Stateful Session Beans

Session beans can be stateful or stateless . A stateless session bean doesn't maintain client state across method calls. If a client makes a series of method calls or transactions with the stateless bean, the bean should be in the same effective state at the start of each method call or transaction. Our ProfileManagerBean is implemented as a stateless session beanthe key signal of this is the use of the Stateless value for the session-type parameter in its deployment descriptor in Example 6-5. The stateless session model makes sense for the ProfileManager: the component doesn't need to keep any client-specific state to perform its function. It just locates a profile for a named user and returns it, and then it's out of the picture.

Since stateless beans don't have any client state, they are entirely interchangeableany instance of a stateless bean of a given type can be used to respond to a client request. And that's exactly how an EJB container manages stateless beansit keeps a pool of precreated beans on the server, and when a client request comes in, the container picks an instance at random, effectively, and invokes the required method on it. Stateless beans also don't need to be passivated since they have no state that needs to be restored when they're reactivated. The container simply destroys any stateless session beans it feels are no longer needed.

A stateful session bean, on the other hand, does maintain client-specific state that can be accessed and changed directly by a client. So a client that creates a stateful session bean owns it for the life of the bean, and no other clients ever get access to it. The bean stays active in the container until the client removes it or until the client's reference to the bean expires (e.g., the client dies and the lease on the remote reference expires), whichever comes first. Again, the container won't associate that particular bean instance with any other clientthe client that created it owns it for its lifetime.

To illustrate the difference between stateless and stateful session beans, let's take our stateless ProfileManagerBean and convert it to a stateful session bean. The ProfileManagerBean is stateless because all it does is accept requests for user profiles and return the profiles directly to the client as Profile objects, which are Serializable JavaBean objects. The client then interacts with the Profile directly, and the Profile holds the conversational state for the client, in the form of the values of the profile entries.

We can provide the same functionality by merging the stateless session ProfileManager EJB and the Profile Java bean into a single stateful session Profile EJB. Instead of creating a reference to a ProfileManager and calling its getProfile( ) business method to get a Java bean, the clients create a stateful Profile EJB directly using its home interface.

Example 6-6 shows the remote interface for the Profile EJB (we won't implement a local interface for this example). It's similar to the interface for the Profile Java bean we used in the stateless ProfileManager example. It has setEntry( ) and getEntry( ) methods that access entries using their names. The Profile EJB also has accessors for the name of its user.

Example 6-6. Remote client interface for the Profile EJB
 import java.rmi.RemoteException; import javax.ejb.EJBObject;   public interface Profile extends EJBObject {   // Get the name of the user associated with this profile   public String getName(  ) throws RemoteException;   // Look up an entry by name   public String getEntry(String name) throws RemoteException;   // Set an entry value   public void setEntry(String name, String value) throws RemoteException; }

We'll need a home interface that clients can use to create these profiles. It's shown in Example 6-7we provide only a single create( ) method, taking the name of the user who owns the profile. Notice that the create( ) method throws the exceptions required by the EJB standard (RemoteException, because this is a remote home interface, and CreateException), but it also throws an application-specific exception, NoSuchPersonException. We defined this exception for this application (it indicates that the named user could not be found on the server). We can add any application-specific exceptions that we want to create( ) methods on home interfaces, as long as we also include them in the signature of the corresponding ejbCreate( ) methods on the bean implementation class.

Example 6-7. Remote home interface for the Profile EJB
 import java.rmi.RemoteException;   import javax.ejb.CreateException; import javax.ejb.EJBHome;   public interface ProfileHome extends EJBHome {   // Create a profile for a named person. Throws an exception if the person's   // profile can't be found.   public Profile create(String name)     throws RemoteException, CreateException, NoSuchPersonException; }

Creating a stateful session implementation of this Profile EJB is much the same as creating the implementation of the ProfileManager EJB. We need to provide all the same container callbacks because they are both session EJBs, we need to implement ejbCreate( ) methods for any create( ) methods on the home interface(s), and we need to implement the business methods exposed in the client interface(s). We won't show all the container callbacks here because they're much the same as the earlier ProfileManager example, and the full details can be found in the source code bundle for the book.[*] Our home interface in Example 6-7 has a single create method, so we need a corresponding ejbCreate( ) method:

[*] You can download the code bundle for this book from http://www.oreilly.com/catalog/javaentnut3.

 // Create method with name of profile owner public void ejbCreate(String name) throws NoSuchPersonException {   mName = name;   System.out.println("Profile EJB created for " + mName + "."); }

The method implementation simply stores the username into an instance variable on the bean and prints a diagnostic message.

We also need to provide implementations of the business methods exposed in the client interface in Example 6-6:

   // Get the name associated with this profile   public String getName(  ) {     return mName;   }     // Get the value for a particular property in the profile   public String getEntry(String key) {     return mEntries.getProperty(key);   }     // Change a value in the profile   public void setEntry(String key, String value) {     mEntries.put(key, value);   }

Deploying this bean is very much like deploying our ProfileManager example. We need to put its details into the deployment descriptor as a <session> element within the <enterprise-beans> element of the ejb-jar.xml file. The key difference here is that we need to specify a value of Stateful for the <session-type> element, to instruct the container that it should manage this EJB using the stateful session bean model (e.g., clients own the beans they create, no other client gets access to an instance created by another client, and so on). We then package the ejb-jar file and perform the rest of the deployment steps as required by our particular EJB container.

Clients use the Profile bean much the same way as the ProfileManager. They first look up its home interface using a JNDI call to the EJB container, then create a Profile EJB using the home stub's create( ) method. This gives them a client stub that they can use to set and get profile entries. An example client use scenario is shown here:

 // Get the Profile bean's home interface ProfileHome pHome = (ProfileHome) context.lookup("ejb/ProfileHome"); // Create a profile for a person System.out.println("Creating profile for " + name); Profile profile = pHome.create(name); // Get/set some entries in the profile System.out.println("Setting profile entries for " + name); profile.setEntry("favoriteColor", "blue"); profile.setEntry("language", "German"); System.out.println("Getting profile entries for " + name); System.out.println("\tFavorite color: " +                    profile.getEntry("favoriteColor")); System.out.println("\tLanguage: " + profile.getEntry("language"));

This example assumes that we've deployed the Profile bean's home interface under the name ejb/ProfileHome in the EJB container's JNDI context.

6.6.3. Container Management of Session Beans

Since stateless beans can be used by any client, the container pools stateless beans and doles them out to clients as needed. If new stateless beans are required, the container creates them; when they aren't (e.g., the rate of client requests decreases), they are simply destroyed. To allow the container to fill its pool, any stateless session bean must provide a single ejbCreate( ) method with no arguments. The container can call this whenever it decides another bean is needed in its ready pool.

Stateful beans are tied to the clients that create them, and they do maintain conversational state with their clients, so the container necessarily manages them differently. Stateful beans are created on demand when the container receives client requests for them. The container may still keep a pool of preconstructed instances of a stateful bean, but they aren't ready to accept method requests until a client calls one of the create( ) methods on the home interface, and the container subsequently calls the corresponding ejbCreate( ) method on one of the beans. At this point, the bean is "owned" by the client, and it's not removed until the client explicitly removes it by calling remove( ) on the client interface for the bean or until the client's reference to the bean goes away (the client quits or the bean reference goes out of scope on the client).

Stateful session beans can also be passivated and activated by the EJB container. The container may decide to do this in order to free up runtime resources on the server, for example. Passivating a session bean involves serializing its state and saving it to disk or some other storage area. When the container decides to passivate a stateful session bean, it invokes its ejbPassivate( ) method. The bean can do any cleanup of resources that it deems appropriate before it is serialized (close I/O streams or database connections, release file handles, and so forth). When the container decides to reactivate a passivated session bean, it first deserializes the bean, then invokes the bean's ejbActivate( ) method to give the bean a chance to restore any resources that it may need during runtime.

Stateless session beans aren't passivated or activated by the container since they aren't designed to maintain client state data. Instead, when the container decides a stateless session bean instance is no longer needed, it simply removes it entirely, and all of the stateless session bean's internal state is lost.

6.6.4. Optional Transaction Support

Stateful session beans can optionally receive notification of transaction boundaries from the EJB container. The container can notify the bean when a new client transaction is beginning and when the client transaction has either been completed or rolled back. For more information on EJB transaction management, see "Message-Driven Beans" later in this chapter.

Since session beans don't typically represent persistent shared data and stateful session beans can be accessed only by a single client at a time, user transaction boundaries may not be important in general to session beans. If, however, the session bean is managing database data for the user, it may want to know about the beginning and ending of user transactions, so that it can cache data at the start and commit its database updates at the end. For this reason, the EJB specification allows stateful session beans to optionally implement the javax.ejb.SessionSynchronization interface. By implementing this interface, the session bean indicates that it wants the container to notify it about the beginning and end of transactions.

In this case, the bean must implement the three methods that are declared on the SessionSynchronization interface: afterBegin( ), beforeCompletion( ), and afterCompletion( ). The container calls the bean's afterBegin( ) method just after a new transaction begins. This lets the bean allocate any resources it might need during the transaction and cache database data, for example. Just before the transaction completes, the container calls the bean's beforeCompletion( ) method. In this method, the bean can release any resources or cached data it may have initialized during the transaction. The afterCompletion( ) method is called just after the transaction has completed. The container passes in a boolean value that is true if the transaction was committed and false if the transaction was rolled back. The bean can use this notification to deal with rollbacks, for example, allowing the bean to undo any changes made during the transaction.



Java Enterprise in a Nutshell
Java Enterprise in a Nutshell (In a Nutshell (OReilly))
ISBN: 0596101422
EAN: 2147483647
Year: 2004
Pages: 269

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net