Chapter 20. Developing Business Logic—Session Beans

Introducing Session Beans

A session bean is a synchronous Enterprise JavaBean (EJB) type that enables you to model real-world business logic in the form of a reuseable and portable J2EE component. Hence, a session bean resides completely within the context of an EJB container (WebLogic Server).

The following are the general characteristics of session beans:

  • From a client perspective, a session bean is a nonpersistent object that implements some business logic running on a server.

    Note

    A session bean can be considered an extension of a client that resides on the server.

  • A session bean is not shared among multiple clients. It performs business logic on behalf of a single client.

  • Client access is mediated by the EJB container in which the bean is deployed.

  • The client of a session bean can be a remote client or a local client. Remote clients include Java programs (Java applications, applets, servlets, or JSPs) or non-Java clients, such as CORBA clients. Local clients include other EJBs deployed in the same JVM as the bean.

  • Session beans can be transaction aware.

  • They are not persistent, so they are relatively short lived within the EJB container. A bean’s lifespan is typically less than or equal to its client.

  • They do not represent data in a data store. However, they can be used to access or update such data.

In the J2EE Application Programming Model, session beans are used as process or control objects specific to a client, so they are a candidate J2EE technology for representing business logic and rules and for controlling workflow between other EJB types (entity and message-driven beans).

Note

▸ To learn more about the J2EE Application Programming Model, see Chapter 5, “The J2EE Architecture and APIs,” p. 171.

Session beans can typically be used for processing credit card numbers, trading stocks, implementing shopping carts, and computing advanced algorithms. Overall, a session bean can be used to house rules governing tasks in a business application. Session beans are also intended to be relatively coarse-grained business objects, such as purchase orders, sales orders, or insurance claims. Fine-grained objects, such as line items on a purchase order, should not be modeled as session beans. This has more to do with session beans being remote objects and less to do with any functional limitations.

The Value Proposition of Session Beans

The value and importance of session beans come from the communication interface between clients and session beans. Session beans consist of a bean class and two interfaces—the home interface and the remote interface. These interfaces provide the thin client to a bean, whereas the bean class, which implements the javax.ejb.SessionBean interface, carries out the business logic.

This implementation model allows clients to use the remote interface as a proxy to the EJB and, therefore, reduces the resource consumption and complexity that clients have to bear. In addition, the bean developer benefits by being able to focus primarily on coding business logic, while the EJB container provides the environment (bean classes and interfaces) in which the bean is implemented. As shown in Figure 20.1, at a high level, the EJB container transparently intercepts client calls to a bean’s method, injects management and control infrastructure services to the invocation, and then calls the bean’s method.

The relationship between the container and session bean.

Figure 20.1. The relationship between the container and session bean.

The infrastructure services that the EJB container provides to a session bean can include the following:

  • Java Naming and Directory Interface (JNDI) registration of the bean when deployed

  • Life cycle and state management

  • Authentication and access control through declarative or programmatic security

  • Serializing method calls

  • Bean pooling

  • Transaction management

  • Persistence management

Developers, therefore, do not have to be concerned about implementing these infrastructure services or the underlying details of how the client finds the bean or communicates with the bean. On the whole, bean developers implement business logic via methods in the session bean class, and the EJB container provides functionality for remote access, security, concurrency, transactions, and other infrastructure services the bean requires to achieve its desired behavior.

Note

The goal of the session bean model is to make developing a session bean as simple as developing the same functionality directly in a client.

Session Bean Types

Session beans can be implemented in one of the following state management modes—stateless or stateful. The following sections discuss these bean types, their distinct differences, and their use in applications.

Stateless Session Beans

Stateless session beans contain no conversational state between methods for a specific client. When a client calls a method on a stateless session bean, the bean’s instance variables can contain state, but only for the duration of the call. When the method has completed, the bean instance no longer retains the state. The stateless bean instance can, however, hold state, but its state is not guaranteed to be specific to a calling client. For example, instance variables of a stateless bean instance can include an open database connection or an object reference to an EJB object.

However, when stateless bean instance are not involved in servicing a client-called method, they are all considered identical from the client’s perspective. Hence, there is no fixed mapping between clients and stateless instances. This allows the EJB container to delegate a client-called method to any available stateless bean instance. For example, the EJB container can delegate requests from the same client within the same transaction to different instances of the stateless bean between remote method calls.

In general, an EJB container needs to retain only the number of stateless bean instances required to service the current client load. Because of client “think time,” the number of stateless session beans is usually much smaller than the number of active clients. The EJB container typically tries to minimize the resources needed to support stateless session bean clients by creating and destroying the bean instance on an as-needed basis.

Note

WebLogic Server can pool identical EJBs, such as stateless session beans and message-driven beans, increasing the J2EE application’s scalability and performance.

When to Use Stateless Session Beans

Stateless session beans are commonly used for procedural tasks that can be accomplished in a single client request. These tasks are sometimes referred to as Model Reuseable Service Objects—any business object providing a generic type of services to its clients. A typical example is a business task that requires returning a list of books by author. Likewise, an application requiring workflow or state management could be modeled with stateless session beans. This application might require chaining session beans to accomplish the task. Chaining stateful session beans becomes a problem when one of the session beans times out or generates an exception. For instance, if three stateful session beans are chained together and the second one in the chain times out, the state trailing the second bean instance would be lost. Because stateless session beans do not maintain conversational state, losing state would not be an issue. The EJB container would simply assign another bean instance without the client being aware of the transition.

Also, the Facade pattern is based on session beans providing a higher-level entry point into a system; what transpires in the subsystem is hidden from the client. This allows the client to access an object’s method at the entry point, thus enabling the method to carry out all underlying tasks in the subsystem. It is important to model session beans as a Facade pattern to take advantage of performance efficiencies. Because EJBs are remote objects, it is best for the client to call only the unified interface to the system, thus reducing the number of remote calls. Having session beans call individual EJB objects might not result in a remote call, as WebLogic Server is optimized to make local method calls instead of remote calls when possible.

Stateful Session Beans

Stateful session beans are similar to stateless session beans, except they contain conversational state on behalf of a specific client; this state must be retained across invoked methods and transactions. A stateful session bean retains a client’s conversational state by storing the state as attributes of the bean. It is the EJB container’s responsibility to ensure that subsequent method calls by a client are routed to the same instance of a stateful bean.

Stateful session beans are memory consumers because state has to be maintained within the bean instance. Therefore, to efficiently manage stateful session beans, the EJB container might need to temporarily transfer the state of an idle stateful session bean instance from memory to disk. This transfer is called instance passivation. The transfer back to memory is called activation. The container can passivate a stateful session bean instance only when the instance is not in a transaction.

Note

A session object’s conversational state might contain open resources, such as open database connections. A container cannot retain these open resources when a session bean instance is passivated. The session bean developer must close and open resources in the ejbPassivate() and ejbActivate() methods.

When to Use Stateful Session Beans

Stateful session beans are appropriate in the following application situations:

  • The need to maintain client state—Stateful session beans enable you to maintain conversational state about a specific client, so they can be used whenever a server-side business object has to represent client state information. However, because each stateful bean is tied to a client request (unlike stateless beans), it cannot be pooled, so be careful when using stateful session beans.

  • Representing workflow scenarios—Business objects that manage the interaction of modules or submodules across a transaction can easily be represented as stateful beans. These objects are usually tied to a single client request and must maintain state information; these characteristics are typical of a stateful EJB.

  • Represent short-lived, nonpersistent objects—Unlike entity beans, stateful beans are not persistent and generally live for the lifetime of the client request to which they are attached. They cannot be re-created after the client’s session with the server is over, and even a server failure can force the death of stateful session beans.

For example, a client’s interaction between the browser and the Web server follows the request/response model. Because HTTP is considered connectionless and stateless, after the server has responded to the client’s request the connection is dropped and forgotten. Using stateful session beans in a Web-based application provides a mechanism for storing the client’s interaction with the server. A shopping cart in an e-commerce Web site is a good example of using stateful session beans. Other examples include an ATM account transfer application, an airline reservation system, and an online book store.

Differences Between Stateless and Stateful Session Beans

Even though the major difference between stateless and stateful sessions beans is based on maintaining conversational state between the client and the bean instance, Table 20.1 compares the primary characteristics of these two bean types.

Table 20.1. Comparing Stateless and Stateful Session Beans

Stateless Session Bean

Stateful Session Bean

Maintains no state.

Maintains state.

The same stateless session bean within the same home has the same object identity, which the container assigns.

Has a unique identity that the container assigns at create time.

Holds no conversational state between methods for a specific client, so it can be pooled.

Holds conversational state between methods for a specific client, so it cannot be pooled.

Not bound to a single client request.

Bound to a single client request.

Does not make use of passivation and activation.

Passivation and activation are intricate parts of its behavior.

Cannot implement the SessionSynchronization interface.

Can make use of the SessionSynchronization interface to synchronize conversational state.

No caching of conversation state. Can cache object state.

Can cache conversational state.

Commonly used for business logic and workflow.

Commonly used for shopping carts.

A Practitioner’s Approach to Understanding Session Beans

Even if you are new to Enterprise JavaBeans, you should easily understand the conceptual purpose and development benefits they provide in enabling client-side business logic to exist as very portable and loosely coupled components. These components exist within the context of a robust, highly available, and performance-oriented application infrastructure, such as WebLogic Platform.

The aspect of EJBs that most people have difficulty understanding is the elements that constitute an EJB and how they exist and are carried out within the EJB container. This section of the chapter is dedicated to giving you a thorough understanding of a session bean’s structural elements, explaining how and why they are developed and deployed in the manner they are, and describing how you can call methods on a session bean from a client. The following sections are a practitioner’s approach to teaching you about session beans, so be prepared for some hands-on development.

The journey ahead will be fast-paced, as shown in Figure 20.2.

What you’ll be learning in this section.

Figure 20.2. What you’ll be learning in this section.

The following list expands on the items shown in Figure 20.2:

  • You will become familiar with the class files associated with a session bean and develop the required class files for a simple session bean example.

  • You will create a Java client to test the session bean after it has been deployed.

  • You will learn about deployment descriptors (ejb-jar.xml and weblogic-ejb-jar.xml) by developing them for the session bean example.

  • You will learn how to build an EJB deployment unit by compiling and packaging the associated class files and deployment descriptors for the session bean example into a single JAR module ready for deployment.

  • You will deploy your session bean application and test its operations.

The Development Elements of a Session Bean

As shown in Figure 20.3, it’s the bean developer’s responsibility to supply the following class files that constitute a session bean:

The elements of a session bean.

Figure 20.3. The elements of a session bean.

  • To provide a remote view of a session bean, you need to implement the following interfaces:

    • Remote interface—Lists bean methods that are exposed to external clients.

    • Home interface—Used by clients to manage a bean’s life cycle.

    The remote view provides location independence to the session bean. For example, a client running in the same JVM as a session bean instance uses the same Java RMI API to access the bean as a client running in a different JVM on the same or different machine.

  • To provide a local view of a session bean, you need to implement the following interfaces:

    • Local interface—Lists bean methods that are exposed to external clients.

    • Local home interface—Used by clients to manage a bean’s life cycle.

    Unlike the remote view, the local view of the session bean is not location independent. Access to the bean requires the client to be located in the same JVM as the session bean. For example, a local client of a session bean can be another enterprise bean (a session bean, an entity bean, or a message-driven bean).

  • The Implementation class, which implements the bean’s actual business logic.

Note

The Implementation class is also commonly referred to as the SessionBean class, as it implements all available methods in the session bean’s remote or local interfaces.

To develop a session bean, you provide the Implementation class file plus class files for the remote view or local view interfaces—or even both. However, unless you are packaging the bean’s client in the same JAR or EAR archive file as the session bean, you need to provide only the remote view interfaces for the bean. The remote view interfaces are required to enable a client to remotely access the bean via RMI/IIOP, which is the standard communication mechanism between distributed Java and J2EE objects, for example, Java clients calling methods on Java remote objects, such as EJBs.

Note

▸ To learn more about RMI, see Chapter 12, “Distributed Processing Using RMI,” p. 385.

Details on using local client view interfaces are discussed later in this chapter in “Using a Local View to Access a Session Bean.” First, to get you better acquainted with the composition of a session bean, the following sections discuss the class files that constitute a simple stateless session bean. This example uses the infamous HelloWorld session bean, and you’ll be creating the following class files:

  • examples.sessionbean.HelloWorld (remote interface)

  • examples.sessionbean.HelloWorldHome (home interface)

  • examples.sessionbean.HelloWorldBean (Implementation class)

To make sure this example is practical, you will also deploy the HelloWorld session bean to WebLogic Server and create a simple Java client to test the bean’s operation.

To set up your working environment for this session bean example, create a working directory on your file system (for example, one named Helloworld), and then create the following subdirectories:

  • src (source files—.java).

  • classes (compiled Java classes—.class).

  • deployment (deployment descriptors for the session bean—ejb-jar.xml and weblogic-ejb.xml).

  • lib (deployment module—.jar).

A build script, discussed later in “Building a Session Bean Deployment Unit,” uses these subdirectories to compile and package the HelloWorld session bean. However, you can create your own specific working directory and subdirectories and modify the build script accordingly.

The Remote Interface

The remote interface acts as a proxy for the session bean instance in the EJB container. The methods defined by the remote interface are literally reflections of the public methods declared in the Implementation class. Each business method defined in the remote interface must have an identical (or counterpart) method in the Implementation class. The business methods defined by the remote interface are what the client calls to process tasks on the session bean instance.

The class that implements a session bean’s remote interface within the EJB container is known as the session EJBObject, which is generated at deployment. The EJBObject class implements the methods of the javax.ejb.EJBObject interface as well as methods specific to the Implementation class. Within the EJB container, it is the responsibility of EJBObject to delegate a client’s method call to the session bean instance.

The following rules must be considered when creating a remote interface for a session bean:

  • The remote interface must extend the javax.ejb.EJBobject interface.

  • All methods must throw the java.rmi.RemoteException exception.

  • Because the remote interface is a Java RMI type interface, all arguments and return values must also be valid types of RMI/IIOP.

  • Each method defined by the interface must match a method in the SessionBean class—same name, number of arguments, argument types, return types, and throws clause.

  • The interface and methods must be declared public.

  • The parameter and return values must be serializable.

Listing 20.1 shows the remote interface for the HelloWorld session bean.

Example 20.1. Remote Interface for the HelloWorld Session Bean

package examples;

import java.rmi.*;
import javax.ejb.*;

/* The methods defined in this interface are the public interface of the
 * HelloWorld session bean.
*/

public interface HelloWorld extends EJBObject
{
/**
  * This method is identical to the one defined in the Implementation class of
  * the Session Bean, except this method must throw a java.rmi.RemoteException.
  */
   public String getHelloWorldMsg () throws RemoteException;
}

Create a Java class file using Listing 20.1, and save the file as HelloWorld.java in your working/src directory.

Tip

In a real-world scenario, you could start by creating the remote interface to define the methods required for implementation in the Implementation class. Alternatively, you could also define methods in the Implementation class first and then declare them via the remote interface. Either way, the main objective is that they are identical.

The Home Interface

The home interface acts as a factory for creating session bean instances and, therefore, exports the methods that provide life cycle services for the bean, such as creation and destruction of the bean. The home interface does not implement any business logic on behalf of the bean or possess any state.

The class that implements a session bean’s home interface within the EJB container is known as the session EJBHome, which is generated at deployment. The EJBHome class implements the methods of the javax.ejb.EJBHome interface as well as the create<METHOD> methods, which call a matching ejbCreate<METHOD> method in the Implementation class. The EJB container makes the session bean’s home interface available to a client through JNDI.

The following rules must be considered when creating a home interface for a session bean:

  • The home interface must extend the javax.ejb.EJBHome interface.

  • Each create method must be named create<METHOD>, and it must match one of the ejbCreate<METHOD> methods defined in the SessionBean class. The matching ejbCreate<METHOD> method must have the same number and types of arguments. However, a stateless session bean’s home interface must define exactly one create() method with no arguments that’s used to instantiate the bean.

  • The return type for a create<METHOD> method must be the session bean’s remote interface.

  • The create<METHOD> must throw the javax.ejb.CreateException and java.rmi.RemoteException exceptions.

  • The interface and methods must be declared public.

Listing 20.2 shows the home interface for the HelloWorld session bean.

Example 20.2. The Home Interface for the HelloWorld Session Bean

package examples;

import java.rmi.*;
import javax.ejb.*;

/* Defines the methods for creating an instance of the HelloWorld session
/* bean */

public interface HelloWorldHome extends EJBHome {
/**
 * This create() method corresponds to the ejbCreate() method in the
 * Implementation class of the HelloWorld session bean.
 * The create() method returns the remote interface of the HelloWorld
 * session bean.
 */
  public HelloWorld create() throws CreateException,RemoteException;
}

Create a Java class file using Listing 20.2, and save the file as HelloWorldHome.java in your working/src directory.

The Implementation Class

As a bean developer, you implement all business logic for a session bean within the Implementation class, which is defined by the remote interface. All Implementation classes must implement the javax.ejb.SessionBean interface. The EJB container uses the setSessionContext() method of the SessionBean interface to associate a session bean instance with its context.

The following rules must be considered when creating the Implementation class for a session bean:

  • The class must implement the javax.ejb.SessionBean interface.

  • The class must be declared as public.

  • The class must have a public constructor that takes no parameters; this constructor is used to create the session bean instance.

  • The class must implement the business methods defined in the remote interface and the ejbCreate() methods in the home interface.

  • Each business method must be defined as public.

Note

The SessionBean class is allowed to implement other methods (for example, helper methods called internally by business methods) in addition to methods the EJB specification requires.

  • If the class is a stateful session bean, it can optionally implement the javax.ejb.SessionSynchronization interface.

  • The bean developer must implement all the following methods defined in the SessionBean interface:

    • The ejbActivate() and ejbPassivate() methods must be implemented. For stateless session beans, the EJB container does not use these callback methods, so they can be left empty.

    • The ejbRemove() method must be implemented.

    • The setSessionContext() method must be implemented.

The following rules must be considered when creating ejbCreate() methods for the Implementation class:

  • The ejbCreate() method must be implemented as it corresponds to the create() method on the home interface.

  • The ejbCreate() method must be declared as public.

  • The ejbCreate() method must not be declared as final or static.

  • The ejbCreate() method must return void.

  • The ejbCreate() method can throw javax.ejb.EJBException or javax.ejb.CreateException exceptions.

Listing 20.3 shows the Implementation class for the HelloWorld session bean.

Example 20.3. The Implementation Class for the HelloWorld Session Bean

package examples;

import javax.ejb.*;

/** The Implementation class for the HelloWorld session bean */

public class HelloWorldBean implements SessionBean
{
 /**
  * The session context is provided by the EJB container. A session bean must
  * retain its context.
. */
    private SessionContext ctx;

/** An EJB must have a public, parameterless constructor */
    public HelloWorldBean() {}

/** Implement a simple logging mechanism to stdout */
    private void log(String s) {
      if (true) System.out.println(s);
    }
 /**
  * This method is required by the EJB specification,
  * but is not used in this example. The container uses this method
  * to activate a stateful session bean after the bean has been
  * passivated using the ejbPassivate() method.
  */
    public void ejbActivate() {}
/**
  * This method is required by the EJB specification,
  * but is not used in this example. The container uses this method
  * to passivate an active stateful session bean.
  */
    public void ejbPassivate() {}
 /**
  * This method is called by the EJB container to remove the
  * session bean from the EJB container.
  */
    public void ejbRemove() {
        log("ejbRemove() called");
    }
/** Called by the EJB container to set the bean's session context. */
    public void setSessionContext(SessionContext ctx) {
        log("setSessionContext called");
        this.ctx = ctx;
    }
 /**
  * Called by the EJB container when a client calls the create() method in
  * the home interface. This method corresponds to the create() method
  * in the home interface of the HelloWorld session bean (HelloWorldHome.java).
  */
    public void ejbCreate() throws CreateException {
        log("ejbCreate() called");
    }
    public String getHelloWorldMsg () {
        log("Bean Method called");
        return ("Stateless SessionBean says Hello World");
    }
}

Create a Java class file using Listing 20.3, and save the file as HelloWorldBean.java in your working/src directory.

The Stubs and Skeletons of Session Bean Interfaces

When you deploy your session bean, method calls to the bean are never handled directly by the remote or home interfaces. Instead, your remote method call to the bean is performed through the collaboration of two EJB container-generated classes called the stub and the skeleton for each interface you implement. Stubs are client-side objects, and skeletons are server-side objects. These classes are responsible for marshaling parameters and return values across the network connection, as shown in Figure 20.4.

The roles of a stub and skeleton in remote communication.

Figure 20.4. The roles of a stub and skeleton in remote communication.

Note

The only restriction for remote methods is that all parameters and return values must be serializable.

A stub is basically a proxy of the remote object and has the same interface as the remote object. The stub is also located on the same machine as a calling client, which enables the client to use its methods in the same manner that it would use methods on the remote object directly. The stub is responsible for marshaling method calls into network messages to a target skeleton object.

Note

Marshal means to serialize parameters so that they can be written to the remote object, which in turn deserializes them back into objects. Marshaling is built into the Java language through the Serializable interface.

The skeleton is an object that deconstructs a network message into its method call. After deconstructing a message, the skeleton handles the logic for calling an equivalent method on the remote object that runs on the same machine as the skeleton.

The skeleton also takes the return value of the method call and converts it to a network message that can be sent back to the stub.

Because a session bean implements two interfaces (remote and home), all remote method calls to a session bean are handled through two sets of stubs and skeletons:

  • The home stub and home skeleton

  • The remote stub and remote skeleton

These stubs and skeletons are auto-generated and implemented by the EJB container when the session bean is deployed to WebLogic Server.

These home and remote stubs and skeletons work in concert to enable a client to remotely call a method on the session bean (see Figure 20.5).

The roles of home and remote stubs and skeletons.

Figure 20.5. The roles of home and remote stubs and skeletons.

The following list explains the numbered callouts in Figure 20.5:

  1. During the startup of WebLogic Server, the home stub of every deployed bean is placed into the JNDI naming service. From here, a client can download the home stub to access a bean’s home interface.

  2. The client uses the home stub to communicate with its home skeleton, which is controlled by the EJB container, to perform the following tasks:

    • Create a bean instance.

    • Provide state to the bean.

    • Associate a client context with the bean.

    • Create a remote skeleton and stub.

  3. The home skeleton returns the remote stub specific to the client via its associated home stub.

    Note

    The skeleton acts as a listener for calls made on the home interface.

  4. After the client has obtained the remote stub, any operations called on the remote stub are communicated to the remote skeleton, which is then delegated to the bean in the container.

Using a Local View to Access a Session Bean

The primary difference between local and remote views of a bean is that a local view is optimized for accessing a bean by bypassing the need to use RMI for communicating with the bean. Because RMI is not used for communication, a local client accesses a session bean through the bean’s local interface or accesses an entity bean through the bean’s local home interface.

The container provides classes that implement the bean’s local and local home interfaces, as follows:

  • The class that implements a session bean’s local interface within the EJB container is known as the session EJBLocalObject, which is generated at deployment. The EJBLocalObject class implements the methods of the javax.ejb.EJBLocalObject interface as well as business methods specific to the session bean. EJBLocalObject is the local version of EJBObect, which is used to delegate requests to the session bean.

  • The class that implements a session bean’s local home interface within the EJB container is known as the session EJBLocalHome, which is generated at deployment. The EJBLocalHome class implements the methods of the javax.ejb.EJBLocalHome interface as well as the create<METHOD> methods specific to the session bean. EJBLocalHome is the local version of EJBHome, which is used to manage the session bean’s life cycle.

Table 20.2 explores some additional differences between local and remote views to provide guidance on which view you should use to implement a session bean.

Table 20.2. Differences Between Local and Remote Views of Session Beans

Remote Calls to a Bean (Remote View)

Local Calls to a Bean (Local View)

Remote calls involve pass-by-value. The objects passed as parameters on remote calls must be serializable.

Local calls involve pass-by-reference and do not need to be serializable. Hence, the state of any Java object passed as an argument or a result can potentially be shared by the object or client.

The remote programming model provides location independence and flexibility for distributing components within a networked environment, so it provides a loose coupling between the client and bean.

Because local calls involve pass-by-reference, the local client and the bean providing the local view must be located in the same place. The local client and bean, therefore, are tightly coupled. The client must be in the same JVM and application as the bean.

Remote calls can be expensive, involving network latency; network, client, and server software overhead; argument copying; and so on.

Because of this overhead, the remote programming model is typically used for relatively coarse-grained component access between a client and a bean, in which only a few method calls are required to complete a task.

Method calls are optimized and faster because they do not use RMI and occur in the same JVM as the client and remote object. This lightweight access is ideal for fine-grained component access, in which a large number of method calls to a bean are required to complete a task.

The client must explicitly program handlers for remote exceptions.

Remote exceptions are not applicable; however, application exceptions still are.

Remote interfaces can implement load balancing or failover.

Local interfaces cannot implement load balancing or failover.

The local and local home interfaces for the HelloWorld session bean are provided in Listings 20.4 and Listing 20.5.

Example 20.4. The Local Interface for the HelloWorld Session Bean

package examples;

import javax.ejb.*;
/**
 * This is the HelloWorld bean's local interface.
 */
public interface HelloWorldLocal extends EJBLocalObject
{
 /**
  * This method is identical to the one defined in the remote interface of the
  * session bean, except this method does not throw a java.rmi.RemoteException.
  */

  public String getHelloWorldMsg();
}

Example 20.5. The Local Home Interface for the HelloWorld Session Bean

package examples;

import javax.ejb.*;

/**
 * This is the local home interface for the HelloWorld bean.
 */
public interface HelloWorldLocalHome extends EJBLocalHome
{
/**
 * This create() method corresponds to the ejbCreate() method in the
 * Implementation class of the HelloWorld session bean.
 * The create() method returns the local interface.of the HelloWorld
 * session bean. As you can see, remote exceptions are not applicable for
 * local home interfaces.
 */
    HelloWorldLocal create() throws CreateException;
}

Developing a Test Java Client for Your Session Bean

Unit testing your J2EE components after they’re deployed is always the best practice, and this simple session bean is no exception. Because the HelloWorld session bean has only one business method, getHelloWorldMsg(), a simple Java client is required to test this method’s operation. Listing 20.6 shows the code for this Java client, and it has been fully commented to explain the processes of locating the home and remote interfaces and implementing the session bean’s method.

Example 20.6. The Test Java Client for the HelloWorld Session Bean

package examples;

import java.rmi.*;
import javax.rmi.PortableRemoteObject;
import javax.naming.*;
import java.util.*;

/**
 * This class is an example of client code that calls
 * methods on a simple stateless session bean.
 */
public class HelloWorldClient {

        private static Context createJNDIContext()
        throws NamingException, RemoteException {

        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
                        "weblogic.jndi.WLInitialContextFactory");
        env.put(Context.PROVIDER_URL,"t3://localhost:7001");

        Context context = new InitialContext( env );
        return context;
    }
     /**
     * Main method to unit test the HelloWorld API
     */

    public static void main(String[] args) {
        try
        {

         // use JNDI to look up the home interface for HelloWorld
        Context context = createJNDIContext();

             // You could use the following statement to retrieve
             // the HelloWorld home

        /* HelloWorldHome home =
            (HelloWorldHome)
                          context.lookup("examples.HelloWorldEJB"); * /

             // However, using javax.rmi.PortableRemoteObject
             // allows you to narrow the scope
             // to the home interface

            HelloWorldHome home = (HelloWorldHome )
                                          PortableRemoteObject.narrow(
                                          context.lookup("examples.HelloWorldEJB"),
                                          examples.HelloWorldHome.class ) ;


            HelloWorld hello = home.create();

            /*
             * The EJBObject will delegate the call to the HelloWorld
             * session bean, receive the result, and return it to this client.
             */

                        System.out.println(hello.getHelloWorldMsg());

            /*
             * Remove the EJBObject.
             * The container will mark the EJBObject for destruction.
             */
            hello.remove();
        }
        catch( Exception err )
        {
            System.err.println( err.toString() );
            }
    }
}

Developing Deployment Descriptors

Two deployment descriptors are applicable to your session bean example:

  • The ejb-jar.xml deployment descriptor file, which includes information on the session bean’s structure, internal dependencies, and application assembly information, per the J2EE specification.

  • The weblogic-ejb-jar.xml deployment descriptor file, which includes specific information on the session bean’s behavior (such as concurrency, caching, clustering, and security) after it is deployed into WebLogic Server’s EJB container.

Note

The weblogic-cmp-rdbms-jar.xml file is applicable only if you are using Container-Managed Persistence.

The following sections describe these deployment descriptors in the context of the session bean example.

The ejb-jar.xml File

Listing 20.7 provides the ejb-jar.xml deployment descriptor file for the HelloWorld session bean example.

Example 20.7. The ejb-jar.xml File for the HelloWorld Session Bean Example

<!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise
JavaBeans 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>

<!-- Generated XML! -->

<ejb-jar>
  <enterprise-beans>
    <session>
      <ejb-name>HelloWorldEJB</ejb-name>
      <home>examples.HelloWorldHome</home>
      <remote>examples.HelloWorld</remote>
      <local-home>examples.HelloWorldLocalHome</local-home>
      <local>examples.HelloWorldLocal</local>
      <ejb-class>examples.HelloWorldBean</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
    </session>
  </enterprise-beans>

  <assembly-descriptor>
    <container-transaction>
      <method>
        <ejb-name>HelloWorldEJB</ejb-name>
        <method-name>*</method-name>
      </method>
      <trans-attribute>Required</trans-attribute>
    </container-transaction>
  </assembly-descriptor>

</ejb-jar>

Table 20.3 describes the primary tag elements in Listing 20.7’s deployment descriptor that you should become familiar with.

Table 20.3. Tag Elements in the ejb-jar.xml File for the Session Bean Example

Element

Description

<ejb-name>

Specifies a unique name for the EJB, used to identify the bean in deployment descriptors.

<home>

Specifies the fully qualified name of the home interface.

<remote>

Specifies the fully qualified name of the remote interface.

<local-home>

Specifies the fully qualified name of the local home interface.

<local>

Specifies the fully qualified name of the local interface.

<ejb-class>

Specifies the fully qualified name of the EJB class.

<session-type>

Specifies the type of session bean—stateless or stateful.

Create your ejb-jar.xml file using Listing 20.7, and save the file in your working/deployment directory.

The weblogic-ejb-jar.xml File

Listing 20.8 provides the weblogic-ejb-jar.xml deployment descriptor file for the HelloWorld session bean example.

Example 20.8. The weblogic-ejb-jar.xml File for the HelloWorld Session Bean Example

<!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems,
Inc.//DTD WebLogic 7.0.0 EJB//EN'
'http://www.bea.com/servers/wls700/dtd/weblogic-ejb-jar.dtd'>

<!-- Generated XML! -->

<weblogic-ejb-jar>
  <weblogic-enterprise-bean>
    <ejb-name>HelloWorldEJB</ejb-name>
    <stateless-session-descriptor>
      <pool>
        <initial-beans-in-free-pool>5</initial-beans-in-free-pool>
      </pool>

      <stateless-clustering>
        <home-is-clusterable>False</home-is-clusterable>
        <stateless-bean-is-clusterable>False</stateless-bean-is-clusterable>
        <stateless-bean-load-algorithm>RoundRobin</stateless-bean-load-algorithm>
      </stateless-clustering>

    </stateless-session-descriptor>

    <transaction-descriptor>
    </transaction-descriptor>

    <enable-call-by-reference>True</enable-call-by-reference>
    <jndi-name>examples.HelloWorldEJB</jndi-name>
    <local-jndi-name>examples.HelloWorldEJBLocal</local-jndi-name>
  </weblogic-enterprise-bean>
</weblogic-ejb-jar>

Table 20.4 describes the primary tag elements in Listing 20.8’s deployment descriptor that you should become familiar with.

Table 20.4. Tag Elements in the weblogic-ejb-jar.xml File for the Session Bean Example

Element

Description

<ejb-name>

Specifies the name of the bean assigned in the ejb-jar.xml file.

<initial-beans-in-free-pool>

Specifies how many instances of the bean should be created by the EJB container and placed into the free pool when the bean is deployed.

<home-is-clusterable>

When true, the home interface can be deployed on multiple WebLogic Servers in a cluster for high availability.

<stateless-bean-is-clusterable>

When true, the bean can be deployed on multiple WebLogic Servers in a cluster for high availability.

<stateless-bean-load-algorithm>

Specifies the algorithm to use for load balancing between replicas of the EJB home (round-robin, random, or weight-based).

<enable-call-by-reference>

Allows EJB methods called from within the same server to pass arguments by reference.

<jndi-name>

Specifies a JNDI name for a bean.

<local-jndi-name>

Specifies a JNDI name for a bean’s local home.

Create your weblogic-ejb-jar.xml file from Listing 20.8 using a text editor or an XML editor, and save the file in your working/deployment directory. You can also use WebLogic Builder to create and validate your deployment descriptors.

Building a Session Bean Deployment Unit

Now that you have created your HelloWorld session bean class files and deployment descriptors, the next step is to build your deployment unit (JAR file), which requires you to do the following:

  1. Compile the EJB classes by using the javac compiler from the command line.

  2. Add the deployment descriptor files to the compiled unit by using the jar utility to create a temporary archive file.

  3. Generate a deployment unit (JAR) that includes the following:

    • The container’s classes, which are internal WebLogic Server–specific class files that WebLogic Server uses to access the bean.

    • The implementation of the home, remote, and local interfaces.

This task is performed with the weblogic.ejbc utility, which generates container classes and implementation classes by inspecting the bean’s Implementation class file and remote and home interfaces and by examining the session bean’s deployment descriptors (see Figure 20.6).

Use weblogic.ejbc to generate the WebLogic container classes.

Figure 20.6. Use weblogic.ejbc to generate the WebLogic container classes.

To perform these tasks, it is a good practice to create a build/make script that can automate the whole build process for you. The build script (build.cmd) for compiling, packaging, and generating the container classes is shown in Listing 20.9.

Example 20.9. An Example of a Build Script

@rem *******************************************************
@rem Cleaning working area
@rem *******************************************************

echo y | rmdir /s classes
echo y | rmdir /s lib
mkdir classes
mkdir lib

@rem *******************************************************
@rem Compiling the session bean files
@rem *******************************************************

javac -d classes src*.java

@rem *******************************************************
@rem Copy deployment descriptors into the META-INF directory
@rem *******************************************************

mkdir classesMETA-INF
copy deployment*.xml classesMETA-INF

@rem *******************************************************
@rem Create the temporary .jar file
@rem *******************************************************

cd classes
jar cf ..lib	emp.jar *
cd ..

@rem *******************************************************
@rem Generating the container classes and creating the deployment
@rem unit
@rem *******************************************************

cd lib
java weblogic.ejbc -keepgenerated temp.jar HelloWorld.jar
del temp.jar
cd ..

Tip

You can view the contents of the generated container class in HelloWorld.jar by using a decompression utility, such as WinZip.

Deploying Your Session Bean

You can use two techniques to deploy your HelloWorld session bean. The easiest is simply copying the HelloWorld.jar file into the applications directory within your WebLogic Server domain directory. If your WebLogic Server is started in development mode, which is the default, WebLogic Server auto-deploys the JAR file.

The other deployment technique is a more formal procedure using WebLogic Builder or the Administration Console. Follow these steps to deploy your HelloWorld.jar file to WebLogic Server using the Administration Console:

  1. Launch and log in to the Administration Console.

  2. Expand the Deployments node in the left pane.

  3. Right-click the EJB node and click the Configure a New EJB option.

  4. Locate the HelloWorld.jar archive on your file system using the Administration Console’s directory navigation mechanism.

  5. Click [select] to the left of the HelloWorld.jar file.

  6. Select a target server from the Available Servers list box.

  7. Enter a name for the session bean application, such as HelloWorld, to identify it in the Administration Console.

  8. Click Configure and Deploy. The Administration Console displays the Deploy tab, which lists deployment status and activities.

After your session bean has been deployed to WebLogic Server, the EJB container creates five instances of the bean in the free pool, as specified by the <initial-beans-in-free-pool> element in weblogic-ejb-jar.xml. Because logging was enabled in each method of the HelloWorld bean (see Listing 20.6), the methods called to instantiate the bean into the free pool are displayed in WebLogic Server’s stdout.

To test your HelloWorld session bean, follow these steps:

  1. Open a command-prompt window and set your Java environment.

  2. Set the CLASSPATH to include the location of the HelloWorld.jar file, as shown in this statement:

    Set CLASSPATH=HelloWorld.jar;%CLASSPATH%
    
  3. Run the application using the following command, as shown in Figure 20.7:

    Running the test Java client against the HelloWorld session bean.

    Figure 20.7. Running the test Java client against the HelloWorld session bean.

    java examples.HelloWorldClient
    

The Life Cycle of Stateless Session Beans

The WebLogic EJB container completely manages the life cycle of a stateless session bean. As shown in Figure 20.8, a stateless session bean can exist in three states.

The life cycle of a stateless session bean.

Figure 20.8. The life cycle of a stateless session bean.

The legal life cycle operations permitted on stateless session beans’ methods are summarized in Table 20.5 and discussed in the following sections.

Table 20.5. Legal Operations for Stateless Session Bean Methods

Method

Operation

newInstance()

Called by the container and signifies the beginning of the life cycle.

setSessionContext()

Called by the container to pass in environment information.

ejbCreate()

Called by the container to create a bean instance in the method-ready pool.

ejbRemove()

Called by the container to remove an instance of the session bean.

xxxMethod()

Called by the client to process a business request.

ejbPassivate()

Must be implemented in the bean class but not called by the container.

ejbActivate()

Must be implemented in the bean class but not called by the container.

The Does Not Exist State

In the Does Not Exist state, a stateless session bean literally does not exist and has not been instantiated. Also, the stateless bean has no identity. For example, by default, no stateless bean instance exists in WebLogic Server during its boot process.

The Method Ready Pool State

If the container decides to instantiate a stateless session bean, it does the following:

  1. Calls the newInstance() method on the stateless bean class to create a new instance. The EJB container can perform instance creation at any time because there is no direct relationship between a client’s call of the create() method and the creation of a bean instance.

  2. Calls the setSessionContext() method on the new bean instance, passing a SessionContext object as the parameter. The session bean uses this object to communicate with the EJB container.

  3. Calls the ejbCreate() method on the new bean instance to initialize the bean.

Note

A stateless session bean can implement only the no-argument constructor.

The stateless session bean instance is now in the Method Ready Pool state, ready for any client to delegate a method call. While the bean is in this state, it exists within the EJB container’s free pool, which is a repository for stateless beans instantiated by the EJB container. The free pool stores unbound stateless beans that are not active and are processing a method call. WebLogic Server uses the free pool to improve performance and throughput for stateless beans, including message-driven beans.

When WebLogic Server starts, if stateless session beans have been deployed to the server, the WebLogic EJB container automatically instantiates multiple instances of the beans, as specified by the value of the <initial-beans-in-free-pool> element in weblogic-ejb-jar.xml. These bean instances are placed in the free pool, ready to service incoming remote method calls. Populating the free pool in this manner improves the initial response time for activating a stateless bean instance because initial requests for the bean can be satisfied without generating a new bean instance.

Note

<initial-beans-in-free-pool> defaults to 0 if the element is not defined, which implies that WebLogic Server does not prepopulate the free pool with any stateless bean instances.

The EJB container creates new instances of stateless beans as needed for concurrent and parallel method processing. However, the maximum number of stateless session bean instances that can be accommodated in the free pool depends on two factors:

  • The value of the <max-beans-in-free-pool> element in weblogic-ejb-jar.xml, which places an upper boundary on the number of stateless bean instances the container creates. An upper boundary might be set when a stateless session bean models a session facade, limiting the number of connections to the back-end server components.

  • The number of execution threads available in WebLogic Server to process each remote method call.

Typically, the EJB container no longer needs the bean instance when it needs to reduce the number of stateless bean instances in the method-ready pool. When this happens, the container calls ejbRemove() on the bean, which transitions the bean to the Does Not Exist state. Also, if a RuntimeException occurs within a stateless session bean’s life cycle, the bean instance transitions to the Does Not Exist state. This does not affect the client because the EJB container delegates another bean instance from the pool to service the client.

The Busy or Active State

When a client calls a create() method on the home interface, the container does not necessarily create an instance of the bean. It just returns a remote interface. Only when method calls are made against a bean’s remote interface does the container find a stateless bean instance in the free pool or create an instance to delegate the method call. The stateless bean then remains active throughout the duration of the client’s method call. When that call is completed, the EJB container detaches the bean instance from the client and returns the bean instance to the container’s free pool.

A container serializes calls to each session bean instance. For this reason, if incoming method requests surpass the number of stateless beans, the method requests must wait until the EJB container can create additional stateless bean instances or the active beans have been unbound from their clients and placed back in the free pool.

The Life Cycle of Stateful Session Beans

Because stateful session beans are bound to a specific client and maintain conversational state, WebLogic Server cannot use a free pool mechanism to keep method-ready stateful beans available. Instead, WebLogic Server uses a cache that stores active EJB instances in memory so that they are immediately available to service their client’s method calls.

However, stateful session beans consume memory resources. For this reason, special provisions are required to ensure that fixed memory resources allocated to WebLogic Server do not become constrained by an increasing number of clients calling methods on stateful beans. To accommodate a large stateful session bean client base, WebLogic Server’s EJB container swaps the unused stateful bean instances out to virtual memory by using Java object serialization. This process, known as passivation, conserves memory resources by limiting the number of stateful bean instances that can be in memory at any given time. When a client calls a remote method on a stateful session bean’s remote interface, and the bean instance is discovered to be passivated, the EJB container loads the bean instance back into memory by deserializing the bean instance object. This process is known as activation. Both concepts are critical in understanding a stateful session bean’s life cycle.

As shown in Figure 20.9, a stateful session bean can exist in three states.

The life cycle of a stateful session bean.

Figure 20.9. The life cycle of a stateful session bean.

The legal life cycle operations permitted on stateful session beans’ methods are summarized in Table 20.6 and discussed in the following sections.

Table 20.6. Legal Operations on Stateful Session Bean Methods

Method

Operation

newInstance()

Called by the container and signifies the beginning of the life cycle.

setSessionContext(sc)

Called by the container to pass in environment information.

ejbCreate()

Called by the container to create a bean instance in the method-ready pool.

ejbCreate(args)

Called by the container to create a bean instance in the method-ready pool.

ejbPassivate()

Called by the container before passivation.

ejbActivate()

Called by the container after activation.

ejbRemove()

Called by the container to remove an instance of the session bean.

afterBegin()

Called by the container when invoking a transactional method.

beforCompletion()

Called by the container after a transaction commit has been requested.

afterCompletion(boolean)

Called by the container and gives the status of commit or rollback.

The Does Not Exist State

When WebLogic Server is first booted, no stateful session bean instances exist.

The Method Ready State

As clients look up and obtain references to individual beans by calling Create<Method> on the home stub, WebLogic Server initializes the new stateful bean instances by calling newInstance(), setSessionContext(), and, finally, ejbCreate() on the bean, returning the EJBobject reference to the client. After the bean is created, it is immediately considered to be in a Method Ready state and placed in the cache. Hence, the number of stateful beans that can exist in a Method Ready state is client driven, not controlled by the EJB container. In the Method Ready state, the stateful bean instance serves its client’s method calls and remains in this state until one of the following occurs:

  • The client calls the ejbRemove() method on the stateful bean, at which point the bean transitions to the Does Not Exist state.

  • The container passivates the bean, at which point the bean transitions to the Passivated state. Passivation uses the Not Recently Used (NRU) algorithm by default, which passivates any recently unused stateful beans.

  • The stateful bean is timed out of cache by the container, at which point the stateful bean is in the Does Not Exist state. A WebLogic administrator can specify the amount of time a stateful bean exists before it’s destroyed.

The Passivated State

Immediately before passivation, the EJB container calls the ejbPassivate() method on the stateful bean, which allows the developer to provide code to deallocate open resources, such as JDBC connections, gracefully. The container passivates the bean only after the ejbPassivate() method has been called.

The resources and information that can be preserved for a stateful bean in a Passivated state include the following:

  • JNDI Environmental Naming Context

  • References to the session context

  • References to other beans’ home interfaces

  • References to other beans’ remote interfaces

  • The JTA UserTransaction type

  • Primitive data types and serializable objects

Note

The EJB container activates a stateful bean by calling the bean’s ejbActive() method. The bean developer can add code in this method to allocate resources that were closed during passivation and to initialize transient attributes to the proper values.

Only the WebLogic EJB container can transition a stateful bean into the Passivated state. Therefore, to maintain continuous high performance, WebLogic Server reserves the cache for active and recently used stateful session beans. When a stateful bean no longer meets this criteria, it becomes eligible for passivation. This does not imply that a bean meeting this criteria will be passivated; the EJB container takes other factors, such as constraints on server resources, into consideration before a stateful bean is passivated. However, you can influence passivation of stateful session beans through the weblogic-ejb-jar.xml deployment descriptor elements described in the following sections.

<max-bean-in-cache>

This element specifies the maximum number of stateful beans of a specific class that are allowed in memory. When <max-bean-in-cache> is reached, WebLogic Server begins to passivate some beans that have not been recently used (Least Recently Used [LRU]) by the client. The default value of <max-beans-in-cache> is 100. If <max-beans-in-cache> is reached and all EJBs in the cache are being used by clients, WebLogic Server throws a CacheFullException.

When analyzing ways to increase performance through the <max-bean-in-cache> element, you should analyze the operation of your stateful bean application and include answers to the following questions:

  • How does the stateful bean application relate to the JVM heap size?

  • What is the total number of beans being deployed?

  • What types of EJBs are being deployed: session, message-driven, or entity beans?

  • What is the memory footprint for deployed beans?

  • What is the expected client request load?

Based on these statistics, you can reach a suitable value for the <max-beans-in-cache> element. Ideally, the setting you select should not exceed the available JVM heap memory or bring WebLogic Server to a halt by competing for memory.

<idle-timeout-seconds>

This element defines the maximum length of time a stateful bean should remain in the cache, after which WebLogic Server can remove the bean instance if the number of beans in the cache approaches the limit of <max-beans-in-cache>.

You can specify explicit passivation of stateful EJBs that have reached <idle-timeout-seconds> by setting the <cache-type> element in the weblogic-ejb-jar.xml file, which specifies the order in which stateful beans are removed from the cache. This setting has two values—Least Recently Used (LRU) and Not Recently Used (NRU):

  • If you specify LRU, the container passivates the bean when <idle-timeout-seconds> is reached.

  • If you specify NRU, the container passivates the bean when there is pressure in the cache.

Note

<idle-timeout-seconds> determines how often the container checks to see how full the cache is. The default is 600.

After a stateful session bean instance is passivated, a client must use the EJB instance before <idle-timeout-seconds> is reached. Otherwise, WebLogic Server removes the passivated instance from disk (Does Not Exist state).

Testing the Life Cycle of Stateful Session Beans

In this section, you leverage the skills you have already learned by developing the HelloWorld stateless session bean, but this time you develop a stateful session bean that you influence to go through its life cycle states.

The stateful session bean you’re developing is named “Passivation” and consists of the following class files:

  • examples.Passivation (remote interface)

  • examples.PassivationHome (home interface)

  • examples.PassivationBean (Implementation class)

You’ll also create examples.PassivationClient, the test client class file.

The following list describes how you influence this stateful bean to transition through its life cycle states:

  • The test client will create multiple instances (50, for instance) of the Passivation stateful session bean.

  • Each instance of the stateful bean maintains a conversation with the client by incrementing a simple counter and returning the value to the client thread.

  • You cause an instance of the stateful bean to be idle for a while by sleeping the client thread for a short period.

  • You modify the <idle-timeout-seconds> and <max-beans-in-cache> elements in the weblogic-ejb-jar.xml file to cause the EJB container to passivate and activate the stateful bean instances.

To develop this example, follow these steps:

  1. Set up a new working directory and subdirectory structure, using the same structure as the earlier HelloWorld example.

  2. Create the following class files and save them into the working/src directory:

    • Use Listing 20.10 to create the home interface for a stateful bean.

    Example 20.10. The Home Interface of the Passivation Stateful Bean

    package examples;
    
    import javax.ejb.*;
    import java.rmi.RemoteException;
    
    public interface PassivationHome extends EJBHome {
    
      Passivation create(int val) throws RemoteException, CreateException;
    }
    
    • Use Listing 20.11 to create the remote interface for the stateful bean.

    Example 20.11. The Remote Interface of the Passivation Stateful Bean

    package examples;
    
    import javax.ejb.*;
    import java.rmi.RemoteException;
    
    public interface Passivation extends EJBObject {
    
      public int count() throws RemoteException;
    }
    
    • Use Listing 20.12 to create the Implementation class for the stateful bean.

    Example 20.12. The Implementation Class for the Passivation Stateful Bean

    package examples;
    
    import javax.ejb.*;
    
    public class PassivationBean implements SessionBean {
    
        // The current counter will be the conversational state.
    
        public int val;
    
        public int count() {
            System.out.println("count()");
            return ++val;
        }
    
        public void ejbCreate(int val) throws CreateException {
            this.val = val;
            System.out.println("ejbCreate()");
        }
    
        public void ejbRemove() {
            System.out.println("ejbRemove()");
        }
    
        public void ejbActivate() {
            System.out.println("ejbActivate()");
        }
    
        public void ejbPassivate() {
            System.out.println("ejbPassivate()");
        }
    
        public void setSessionContext(SessionContext ctx) {
        }
    }
    
    • Use Listing 20.13 to create the test client for the stateful bean.

    Example 20.13. The Test Client for the Passivation Stateful Bean

    package examples;
    
    import java.rmi.*;
    import javax.rmi.PortableRemoteObject;
    import javax.naming.*;
    import java.util.*;
    
    public class PassivationClient {
    
        private static Context createJNDIContext()
            throws NamingException, RemoteException {
    
            Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY,
                          "weblogic.jndi.WLInitialContextFactory");
            env.put(Context.PROVIDER_URL,"t3://localhost:7001");
    
            Context context = new InitialContext( env );
            return context;
        }
        public static void main(String[] args) {
            try
            {
             // use JNDI to look up the home interface for HelloWorld
             Context context = createJNDIContext();
                PassivationHome home = (PassivationHome )
                                              PortableRemoteObject.narrow(
                                              context.lookup("examples.PassivationEJB"),
                                              examples.PassivationHome.class );
                /*
                 * An array to hold 50 count EJB objects
                 */
                Passivation count[] = new Passivation[50];
                int countVal = 0;
                /*
                 * Create and count() on each member of the array
                 */
                System.out.println("Instantiating Stateful Beans...");
                for (int i=0; i < 50; i++) {
                    /*
                     * Create an EJBObject and initialize
                     * it to the current count value.
                     */
                    count[i] = home.create(countVal);
                    countVal = count[i].count();
                    System.out.println(countVal);
                    /*
                     * Sleep for 1 second
                     */
                    Thread.sleep(1000);
                }
                /*
                 * Call count() on each EJB object to
                 * ensure the beans are activated if in a passivated state
                  */
                System.out.println("Calling count() on beans...");
                for (int i=0; i < 50; i++) {
                    /*
                     * Add 1 and print
                     */
                    countVal = count[i].count();
                    System.out.println(countVal);
                    /*
                     * Sleep for 1 second
                     */
                    Thread.sleep(1000) ;
                }
                /*
                 * Remove objects
                 */
                for (int i=0; i < 50; i++) {
                    count[i].remove();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
  3. Use Listing 20.14 to create the ejb-jar.xml deployment descriptor and save it in the working/deployment directory.

    Example 20.14. The ejb-jar.xml Deployment Descriptor for the Passivation Stateful Bean

    <!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise
    JavaBeans 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>
    
    <!-- Generated XML! -->
    
    <ejb-jar>
      <enterprise-beans>
        <session>
          <ejb-name>Passivation</ejb-name>
          <home>examples.PassivationHome</home>
          <remote>examples.Passivation</remote>
          <ejb-class>examples.PassivationBean</ejb-class>
          <session-type>Stateful</session-type>
          <transaction-type>Container</transaction-type>
        </session>
      </enterprise-beans>
    
    </ejb-jar>
    

    What differentiates a stateless and stateful session bean at deployment is how the bean is defined in the weblogic-ejb-jar.xml deployment descriptor using the <session-type> element.

  4. Use Listing 20.15 to create the weblogic-ejb-jar.xml deployment descriptor and save it in the working/deployment directory.

    Example 20.15. The weblogic-ejb-jar.xml Deployment Descriptor for the Passivation Stateful Bean

    <!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD
    WebLogic 7.0.0 EJB//EN'
    'http://www.bea.com/servers/wls700/dtd/weblogic-ejb-jar.dtd'>
    
    <!-- Generated XML! -->
    
    <weblogic-ejb-jar>
      <weblogic-enterprise-bean>
        <ejb-name>Passivation</ejb-name>
        <stateful-session-descriptor>
          <stateful-session-cache>
            <max-beans-in-cache>45</max-beans-in-cache>
            <idle-timeout-seconds>500</idle-timeout-seconds>
            <cache-type>LRU</cache-type>
          </stateful-session-cache>
    
          <stateful-session-clustering>
          </stateful-session-clustering>
    
        </stateful-session-descriptor>
    
        <transaction-descriptor>
        </transaction-descriptor>
    
        <jndi-name>examples.PassivationEJB</jndi-name>
      </weblogic-enterprise-bean>
    </weblogic-ejb-jar>
    

    The elements of the weblogic-ejb-jar.xml deployment descriptor file that can influence passivation of a stateful session bean are highlighted in Listing 20.15. You can modify these values, however, for the initial test; use the specified values.

  5. Compile and build the Passivation.jar deployment unit using a build script (provided in Listing 20.6).

  6. Deploy the stateful bean to an active WebLogic server by copying the Passivation.jar file into your WebLogic domain’s applications directory.

To test your Passivation stateful session bean, follow these steps:

  1. Open a command-prompt window and set your Java environment.

  2. Set the CLASSPATH to include the location of the Passivation.jar file, as shown in this statement:

    Set CLASSPATH=Passivation.jar;%CLASSPATH%
    
  3. Run the application using the following command, as shown in Figure 20.10:

    Run the test Java client against the Passivation session bean.

    Figure 20.10. Run the test Java client against the Passivation session bean.

    java examples.PassivationClient
    

As shown in Figure 20.10, the EJB container is passivating and activating the stateful bean. You can also use the Administration Console to monitor the activity and status of your deployed stateful session beans (see Figure 20.11).

Monitor the cache, activation, and passivation activity of a deployed session bean from the Administration Console.

Figure 20.11. Monitor the cache, activation, and passivation activity of a deployed session bean from the Administration Console.

Programming Transactions in Session Beans

The WebLogic EJB container provides both Container-Managed and Bean-Managed Transaction support for session beans, which is specified by the <transaction-type> element in the bean’s ejb-jar.xml deployment descriptor. This tag can have the value Bean or Container. Bean implies that the EJB will perform all the transaction management, and Container means that the bean requests the WebLogic EJB container to perform transaction management. The following sections discuss both transaction management techniques.

Note

▸ For a detailed discussion on the Java Transaction API, see Chapter 16, “Managing Java Transactions Using JTA,” p. 527.

Container-Managed Transactions

When Container-Managed Transactions (CMT) are used, the EJB container requires additional information on how and when to start transactions. This information is also provided in the deployment descriptor in the <container-transaction> element. Six keywords define the transaction attribute (see Table 20.7). The transaction attribute can be applied on a per-bean basis or to individual methods within the bean.

Table 20.7. Transaction Attributes for Session Beans

Transaction Attribute

Description

Never

The EJB call cannot participate in a transaction. If the call is made within a transaction, RemoteException is thrown.

NotSupported

The EJB call does not participate in transactions regardless of whether a transaction has been started.

Supports

The EJB call participates in the transaction if one has been started; otherwise, it does not.

Mandatory

The EJB call must occur after a transaction has been started; otherwise, TransactionRequiredException is thrown.

Required

The EJB call participates in the transaction that the client started. If the client has not started a transaction, the EJB container starts a transaction and commits the transaction when the call completes.

RequiresNew

The EJB container always starts a new transaction before calling the EJB method. The EJB container commits the transaction when the call returns.

If no <container-transaction> element is provided in the deployment descriptor, the WebLogic EJB container defaults to Supports for all methods in the EJB. An example of the <container-transaction> element from the ejb-jar.xml file is shown in Listing 20.16.

Example 20.16. An Example of the <container-transaction> Element from the ejb-jar.xml File

<container-transaction>
    <method>
        <ejb-name>MySessionBean</ejb-name>
        <method-name>*</method-name>
    </method>
    <trans-attribute>Required</trans-attribute>
</container-transaction>

Listing 20.16 sets the Required transaction attribute for all methods in the MySessionBean bean.

The <method> tag section can have specific method names. To support method overloading, a list of method parameters can be supplied to select a specific method signature. An example of a <container-transaction> element that specifies the Mandatory transaction attribute for the getBalance( String account ) method is shown in Listing 20.17.

Example 20.17. An Example of <container-transaction> Specifying the Mandatory Transaction Attribute

<container-transaction>
    <method>
        <ejb-name>MySessionBean</ejb-name>
        <method-name>getBalance</method-name>
        <method-params>java.lang.String</method-params>
    </method>
    <trans-attribute>Mandatory</trans-attribute>
</container-transaction>

Bean-Managed Transactions

Bean-Managed Transactions (BMT) are indicated when the <transaction-type> element in the deployment descriptor is set to Bean. The EJB must then directly call methods on the UserTransaction object. With CMT, transaction boundaries are set by the client or EJB container. With BMT, the EJB gets a reference to the UserTransaction object by calling getUserTransaction() on the SessionContext object. The SessionContext object is passed to the EJB through the setSessionContext() method. The EJB can call the begin, commit, and rollback methods on the UserTransaction object. A stateless session bean must commit or roll back every transaction before returning from the method call. A stateful session bean can keep a transaction active across multiple method calls.

Keep in mind that although the stateful session bean is caching the client’s conversational state, the state is not considered transactional. Therefore, it is not automatically rolled back to some initial state when the transaction it participates in is rolled back. The bean developer needs to provide logic to accomplish this task.

Note

In CMT, implementing the SessionSynchronization interface gives a stateful session bean additional callback methods to help maintain its state in a transaction. The session bean has the capability to roll its state backward or forward, based on a transaction’s success or failure.

Summary

Session beans are an important component of the J2EE specification, giving you the ability to develop typically client-side business logic within the realm of the EJB container. This chapter has introduced you to the types of session beans you can develop and described their life cycles and differences. You have had the opportunity for hands-on experience in developing stateless and stateful session beans to get you comfortable with the technology.

To continue the discussion of session beans in the context of a WebLogic cluster, read Chapter 25, “Implementing Highly Available and Scalable Solutions Using the WebLogic Cluster.”

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

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