In this article we will look more in depth at Session Beans focusing on key aspects of the both stateless session beans as well as stateful session bean in order to be fully prepared for the Component Developer Exam. We will focus on features generic to both type of session bean as well as the features specific to each. and services of EJB 3, including the major actors: the beans and clients. This includes unique states specific to each beanís lifecycle.

Session Bean Review

In this section we will quickly go into the different aspect of Session beans before we implement two EJB Beans to show both stateless and stateful session beans. Session seans are used to implement some business functionality. The functionality that it implements can be things such as checking credit or debit card details, reservations, fund transfers, financial calculations, etc. Session beans are transient and relatively short lived. In particular, session beans are not persistent; they are not stored in a database or other permanent storage. They are comprised of the following


The Interface

There is the interface where the business methods for the stateless session bean are defined. In general this is also called the contract. This defines what the service will do. It is important to remember that an EJB can have multiple interfaces. Just remember that the same interface can only be used either as @Local or @Remote interface. This is because EJB implementation classes can be polymorphic. If you want to provide a local and remote interface based on the same methods, what you should do is to provide a base object that is common to both that you then extend. An example of this is shown below:

Java Code: Base interface and it's remote extension
public interface MyFinancialCommonBusiness {
    /** 
     * Calculate all arguments * 
     * @return The sum of all arguments 
     */
    double calculate(double... arguments);
}

public interface MyFinancialRemoteBusiness extends MyFinancialCommonBusiness{

}
In the above example, we have created a base interface for doing monte carlo calculations of the yield curve and extended the interface in order to provide a remote version of it. It is the remote version that can be used for implementing the session bean.

The Implementation

This is the part of the session bean that contains the business logic fulfilling the contract outlined in the business interface. It must explicitly include the interface in its class declaration. Unlike with simple POJOs, session bean implementation cannot be abstract and all the declared methods of the interface must be concretely implemented by the class. An example of this is shown in the code below:

Java Code: implementation of remote EJB bean
@Stateless
public class MyFinancialBeanBase implements MyFinancialRemoteBusiness {
       double strike;    // Strike price.
       int s;            // Number of observation times.
       double discount;  // Discount factor exp(-r * zeta[t]).
       double[]muDelta; // Differences * (r - sigma^2/2).
       double[] sigmaSqrtDelta; // Square roots of differences * sigma.
       double[] logS;    // Log of the GBM process: logS[t] = log (S[t]).

    @Override
    public double calculate(double r, double sigma, double strike, double s0,
            int s, double[] zeta) {
           double average = 0.0;  // Average of the GBM process.
           for (int j = 1; j <= s; j++) average += Math.exp (logS[j]);
           average /= s;
           if (average > strike) 
               return discount * (average - strike);
           else 
               return 0.0; 
    }
}
You can have public or protected methods that are not part of the interface of the bean similar to what you can do with normal OO programming. This is quite useful for unit testing of your beans as well as for implementing lifecycle callbacks. In fact, you have the full range of OO programming features since your EJB bean is at heart a POJO.

The Bean Instance

The EJB Container will hold one or more instance of the bean implementation classes of your session bean out of the view of the client. In the case of Stateless session beans, this will be held in a method-ready pool so that they can be efficiently accessed and used in order to improve performance.

The EJB Proxy

Clients do not access the EJB directly but through an EJB Proxy. This proxy provides the same interface to the EJB Bean as the EJB Bean itself has. Rather when the client makes a business call, it is actually a call to the EJB Proxy which in turn invokes the proper business method on the EJB Bean. All the EJB Containers bind all the appropriate Proxy objects into a specific destination in the Global JNDI where a client can do a lookup in order to get a reference to them. The client never realizes that it is not talking to the session bean but to the proxy. The benefit of this level of indirection is that it facilitates the application of many of the EJB container services to the EJB Bean.

Local and Remote Interfaces

The default for most EJB invocations is through a remote interface, What this means is that the client and the EJB Container are not running in the same Java Virtual Machine (JVM). When the client and the EJB Container happen to be running within the same JVM, it is possible to use a local interface. The two main advantages of the local interface over the remote interface are that objects are passed by value instead of by reference and avoiding of the network stack in the call both tending to improve on the performance of the application. Therefore standard best practice is that if you have session beans of an application that is being regularly called by another session bean, if possible colocate them within the same JVM to get a performance boost.

Component Interface

In order to provide backward compatibility to EJB2, the component interfaces has been retained in EJB3 specification. Any application wanting to provide backward compatibility must implement along with the business methods, javax.ejb.EJBObject or javax.ejb.EJBLocalObject. You then need to use one of the create methods of the home interface. Please see article, Tutorial In Depth View of EJB Bean for Component Developer Exam in the section using EJB2 with EJB3 for more information.

Home Interface

In EJB2, the home interface was used to create, find and remove session bean references. In EJB3, it is no longer needed. But for backward compatibility it is still included in the EJB3 specification. If you need to use it, you must extend either the javax.ejb.EJBHome or javax.ejb.EJBLocalHome interfaces. Methods the you create must be prefixed with ďcreateĒ in order to return component interface references.

Endpoint Interfaces

These interfaces to facilitate the EJB business methods use in web services, allow you to access EJB business methods via SOAP from outside the EJB container. The interface is based on the JAX RPC (Java API for XML-RPC) standard as well as those for SOAP and WSDL. The only thing required for this is to annotate the java interface with @javax.jws.WebService.

Naming Conventions to Be Followed

There has been developed a set of common naming conventions that have been defined for all EJB classes. There are shown in the following table

Tutorial: Review of Session Bean for the Component Developer Exam-a3-namingconventionstable.jpg
Table: Naming Conventions for EJB Classes





Session Bean Types

There are two types of session beans. There are there are stateless session beans that hold no client state information throughout the client session and there are stateful session beans that maintain the state of the client throughout the whole client session.

Stateless Session Beans (SLSB)

As stateless session beans are one of the key elements of the Component Developer Exam, we will now look at in depth in order to make sure youíre aware of all the aspects of it that you need to know. As was mentioned previously the stateless session beans donít maintain conversational state. Conversational state is the equivalent of you and me having a conversation. In terms of an JEE 5 application this corresponds to a conversation between the Client (caller) and EJB (service). What this means is that there are no means (i.e. variables) connected with the conversation between the client and the EJB. When the method invocation has completed, no data that has been manipulated is retained. This allows for stateless session beans to be reused. The SLSBs are held in whatís called a method-ready pool for reuse. This means that the EJB container will hold a number of instances of the session bean in a pool so that when there is a client request, an instance can be quickly assigned to handle the client request. This allows for the pool of session bean instances to service a larger number of clients than if they were holding client state or if they needed to be initialized before each use. Some of the typical uses of stateless session beans is for report generation, batch processing or for handling credit or debit card transactions.

Although SLSBs donít hold conversational state, they can hold instance variables that can be used for debugging or logging use of all instances of SLSBs in the system. This state is never visible to the client and in most cases will be different for different bean instances depending on the variables being held. It is for this reason that your instance variable should be generic and not accessed via any API.

Tutorial: Review of Session Bean for the Component Developer Exam-a3-clientstatelesssessionbean.jpg
Figure: Three Client Requests for Stateless Session Beans





The TudoList Application

TudoList is based on an Spring Application that was part of a book called, "Spring par la pratique" by Julien Dubois. We will create a new version of the application based on the EJB3 specification. Tudu Lists is basically a web project management tool for managing todo lists. It allows you to easily access, edit and share todo lists over the web.

Tutorial: Review of Session Bean for the Component Developer Exam-a3-tudoapplication.jpg
Figure: Screen shot of TudoList Application





The Architecture for TudoList

We will focus only on a subset of the three EJB 3 component types across the business logic and persistence layers in order to highlight the functionality of both stateless and stateful session beans. This set of application functionality is shown in figure 2.2.
The functionality represented in figure 2.2 encompasses the ďessentialsĒ of TudoList. The major functionalities not covered are: posting an item for sale, browsing items, and searching for items. Weíll save these pieces of functionality for parts 2 and 3. This includes presenting the entire domain model, which weíll

Tutorial: Review of Session Bean for the Component Developer Exam-a3-tudodomainmodel.jpg
Figure: Domain Model for Tudo Application





Note that the property table is used to holds key parameters of TudoList including the SMTP server address for email. Also the role table only holds two rows. One for the administrator role and the other for user.

The architecture of TudoLists is shown below. Here we have described a typical 3 tier architecture that is used for Java EE 5 EJB3 application.

Tutorial: Review of Session Bean for the Component Developer Exam-a3-tudoapplicationlayers.jpg
Figure: Architecture for TudoList Application





We have the following layers and services provided in the application:
  • Domain Layer
The domain model provides an abstraction of the business domain for the TudoList application. In this layer, we have the entity objects that are used by the EJBs, and the group of Entity Access Objects made of interface and implementations for managing the persistence of domain objects.
  • Service Layer
The service layer holds the business services that performs business processes based on the domain model. There are services for the configuration of the Tudu List application, for managing the users, for managing todo list and for managing todos.
  • Web Layer
The web layer uses Struts Web Framework for the web tier of the application as well as DWR for the parts of the application that uses Ajax.
Defining a Stateless Session Bean

Letís start by creating a stateless session beans for the TudoList Application for configuring the TudoList Application, ConfigurationBusiness. It contains two methods; one for getting a property for configuring a property for email via a key; and a second for updating the email properties. The business interface is shown below:

Java Code: Business interface - Configuration
package com.acme.tudo.buslogic;
import javax.ejb.Local;
import com.acme.tudo.persistence.Property;

@Local
public interface ConfigurationBusiness {

    /**
     * Find a property by key.
     * 
     */
    Property getProperty(String key);
  
    /**
     * Update email properties.
     * 
     */
    void updateEmailProperties(String smtpHost, String smtpPort, String smtpUser, 
            String smtpPassword, String smtpFrom);
}
This type of business interface is perfect for a stateless session bean. Thatís because there is no need to maintain any sort of conversational state for this session bean and the process can be completed in one method call. The ConfigurationBusiness interfaces manages the parameters for the email server. Once it has finished either acquiring the information presently stored on the email configuration or updating it, itís raison díetre is finished and can be placed back in the method ready pool for use by another client. Note that this is a plain old java interface with the @Local annotation to identify it as a local EJB business interface. So there is no need to ensure the all of the parameters and return types implement java.io.Serializable interface, which is required if we had used @Remote annotation, as well as indicating that this EJB can be accessed locally through its interface. The code for the implementation is shown below:

Java Code: Stateless session bean - Configuration Bean
package com.acme.tudo.buslogic;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import com.acme.tudo.persistence.Property;
import com.acme.tudo.persistence.eao.PropertyEAO;

@Stateless(name = "Configuration")
public class ConfigurationBean implements Configuration {

    @EJB
    private PropertyEAO propertyEAO;

    @Override
    public Property getProperty(String key) {
        return propertyEAO.getProperty(key);
    }

    public ConfigurationBusinessBean(){};

    @Override
    public void updateEmailProperties(String smtpHost, String smtpPort,
            String smtpUser, String smtpPassword, String smtpFrom) {
        Property hostProperty = propertyEAO.getProperty("smtp.host");
        hostProperty.setValue(smtpHost);
        propertyEAO.updateProperty(hostProperty);
        Property portProperty = propertyEAO.getProperty("smtp.port");
        portProperty.setValue(smtpPort);
        propertyEAO.updateProperty(portProperty);
        Property userProperty = propertyEAO.getProperty("smtp.user");
        userProperty.setValue(smtpUser);
        propertyEAO.updateProperty(userProperty);
        Property passwordProperty = propertyEAO.getProperty("smtp.password");
        passwordProperty.setValue(smtpPassword);
        propertyEAO.updateProperty(passwordProperty);
        Property fromProperty = propertyEAO.getProperty("smtp.from");
        fromProperty.setValue(smtpFrom);
        propertyEAO.updateProperty(fromProperty);
    }

}
There are a couple of things to note about the code. First is that the java code is very simple. Thatís because it is basically a POJO that is implementing an interface. It is the annotations that provide it with itís classification as a stateless session bean. The key one is the @Stateless annotation that defines ConfigurationBean to the EJB container as a stateless session bean. This means that the EJB container will manage the bean in a manner consistent with the lifecycle of a stateless session bean. It will provide services related to transaction management, pooling, concurrency control and thread safety automatically. As well we can also overlay the session bean with interceptors and security.

Stateless Session Bean Rules

Although stateless session beans are POJOs and can take advantage of the wide variety of features that are possible using object oriented programming, there are still a set of rules that need to be followed for it to be considered as a stateless session bean and to be properly managed by the EJB Container. These rules are the following:
  • The session bean must have at minimum one business interface
  • The session bean must be concrete and avoid using either abstract or final in its definition. Otherwise, the EJB container cannot manipulate it.
  • The session bean must have a no argument constructor in the bean class in order that the container can create the bean instance when the client invokes an EJB.
  • The session bean may subclass another session bean or any POJO.
  • The session beanís business methods and lifecycle callback methods can be defined in itís superclass or in the bean itself.
  • The session bean that is the subclass of another will inherit the annotations related to lifecycle callback methods but not those determining the type of session bean (i.e. @Stateful or @Stateless).
  • The session beanís business methods cannot begin with ďejbĒ. This is primarily to avoid EJB2 compatibility problems as well as some other EJB infrastructure processing.
  • The session beans business methods must all be defined as public. You cannot use neither final nor static in the definition.
  • The remote session beanís business interface must ensure that all the arguments as well as the return type all have implemented java.io.Serializable interface.
[SIZE=3]Client Access to Stateless Session Beans
There are very few limits as to the type of client that can access the stateless session bean since even .NET clients could access if we annotate the bean with @WebService transforming it into a web service. In general though, it will most likely be a java based client. In our example we will be using a Struts 2 action, this is shown below.

Java Code: Struts action class using stateless session bean
package com.acme.tudo.web.
import com.opensymphony.xwork2.ActionContext;
import javax.servlet.http.HttpServletRequest;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ModelDriven;
import com.acme.tudo.domain.Admin;
import com.acme.tudo.buslogic.ConfigurationBusiness;


public class AdministrationAction extends ActionSupport implements ModelDriven<Admin> {

private static final long serialVersionUID = -6659925652584240539L;

private Admin admin = new Admin();
@EJB
private ConfigurationBusiness configurationBusiness;

@Override
public Admin getModel() {
return admin;
}

/**
* To save or update configuration.
* @return String
*/

public String saveOrUpdate()
{**
        String smtpHost = admin.get("smtpHost");
        String smtpPort = admin.get("smtpPort");
        String smtpUser = admin.get("smtpUser");
        String smtpPassword = admin.get("smtpPassword");
        String smtpFrom = admin.get("smtpFrom");
        configurationBusiness.updateEmailProperties(smtpHost, smtpPort, smtpUser,         smtpPassword,smtpFrom);
        return SUCCESS;
}
There are some other interesting things to note as well

EJB 3 dependency injection

The session bean is injected into the class using @EJB annotation which is one of the methods implemented by the SessionContext for the benefit of session beans. It can then access itís method to update the email properties. This annotation works with any component that is registered with the Java EE 5 container. If the container didnít provide this service, we would receive a java.lang.NullPointerException when we tried to call the updateEmailProperties method in listing shown above since the configurationBusiness variable would still be null. So the EJB dependency injection provides ďcustomĒ Java variable instantiation. Think of EJB 3 DI as a high-level abstraction over JNDI lookups.

The Beanís Lifecycle

In my previous article, ďTutorial: In Depth View of EJB Bean for Component Developer ExamĒ we looked at the lifecycle of a stateless session bean. There are basically a number of states that the bean will pass during itís lifecycle.
  1. The bean is instantiated
  2. The container injects the beanís SessionContext if required.
  3. The container performs any other dependency injection needed by any of the beanís metadata
  4. The container invokes a PostConstruct callback method if it is present in the stateless session bean. The PostConstruct method can then be used for initializing any resources used by the bean. The PostConstruct method is only called once during the lifecycle of the instance when it transitions from the does-not-exist state to the method-ready pool.
An SLSB has numerous lifecycle callback methods, or callbacks, that can be used to perform various operations during the life of a stateless session bean. Since these beans are allocated from and returned to the pool on a per-invocation basis, stateless session beans are extremely performance friendly and a small number of bean instances can handle many concurrent clients. Since a stateless bean doesnít hold any conversational state, each call to updateEmailProperties will update the email properties for the user each time, the client isnít concerned with the beanís internal state. So its instance variables will be the same across any two method calls.

In the listing above, the ConfigurationBusinessBean is using an Entity Access Object in order to manage access to the database. In a later post on Persistence, I will provide you with more details about them. They are very similar to Data Access Object. If we were not using them and using JDBC directly it would have bean necessary for us to better manage our resources using the PostConstruct and PreDestroy callbacks are used to manage a JDBC database connection derived from the injected data source. An example of what they would have looked like is shown below:

Java Code: example of stateless session bean using callbacks
@Stateless(name = "ConfigurationBusiness")
public class ConfigurationBusinessBean implements ConfigurationBusiness {
@Resource(name="jdbc/tudoDS") 
private DataSource dataSource; 
private Connection connection;
...
public ConfigurationBusinessBean() {}

@PostConstruct
public void initialize() {
    try{
        connection = dataSource.getConnection();
    } catch (SQLException sqle) { 
         sqle.printStackTrace();
    }
}

....

@PreDestroy
public void cleanup() {
    try { connection.close();
    } catch (SQLException sqle) { 
        sqle.printStackTrace();
    }
}
...
}
Also one key thing to remember is that the bean has a no-argument constructor that the container will use to create instances of ConfigurationBusinessBean EJB object.

Specifying bean business interfaces

A Client application can invoke a stateless session bean in using one of three methods. ways: 1. They can be invoked locally within the same JVM; 2. They can be invoked remotely via RMI; and 3. They can be invoked remotely as web services. These three types of business interfaces correspond to the different access types that each has its own distinct annotation. These annotations are the following:

Local interface


A local interface is designed for clients of stateless session beans that run in the same container (JVM) instance. You can designate an interface as a local business interface by using the @Local annotation. The ConfigurationBusiness interface has this annotation.

Java Code: definition of local business interface
@Local
public interface ConfigurationBusiness {
...
}
Transactions

If you decide that you need to use Bean Manage Transactions, the transactions are being managed using UserTransaction should start and complete within the same method. So you cannot have a transaction that spans two or more methods. This is only allowed with stateful session beans since there is a one to one relation between the bean and the client.

Remote interface

When a client resides outside the EJB containerís JVM instance, you must use a remote interface. If it is a Java client, you can invoke the EJB using Java Remote Method Invocation (RMI). It is a highly efficient, TCP/IP- based remote communication API that automates most of the work needed for calling a method on a Java object across a network. You make an EJB accessible over a remote interface by using the @Remote annotation. The ConfigurationBusiness interface could be made into a remote interface in the following manner:

Java Code: definition of remote business interface
@Remote 
public interface ConfigurationBusiness {
...
}
We could also have the business interface extend java.rmi.Remote interface, but this is entirely optional. As I have mentioned above, all remote business interfaces must have all parameters and return types of interface methods implemented as Serializable. This is because only Serializable objects can be sent across the network using RMI.

Web service endpoint interface

The third type of interface is the web service endpoint interface also known as SEI. This facility makes it very easy to expose a stateless session bean as a SOAP-based web service. The annotation required to make a bean SOAP accessible is the @javax.jws.WebService annotation. I give an example of this using a web service version of the ConfigurationBusiness interface:

Java Code: definition of web service interface
@WebService 
public interface ConfigurationBusiness WS {
    Property getProperty(String key);
    @WebMethod(exclude = "true") 
    void updateEmailProperties(String smtpHost, String smtpPort, String smtpUser, 
            String smtpPassword, String smtpFrom);
}
You can place the @WebService annotation on either the interface or the implementing bean. You then use the @javax.jws.WebMethod annotation on a method to expose it as part of the web service. If there are multiple multiple methods in the bean implementation class with a generated endpoint interface, you need to annotate @WebMethod on those methods you want to expose in the web service. Conversely you can use it on those methods of an EJB that you will expose as a web service that you donít wish to expose. So in the previous listing, the updateEmailProperties method would not be exposed as part of the web service interface.

Multiple business interfaces

Although you cannot mark the ConfigurationBusiness interface with both the @Local and @Remote annotations, you can create local and remote versions of the same interfaces by extending a common base. But you can also extend another interface if you wish. The benefit of this is that you can remove code duplication by creating a business interface that has common methods and business interfaces that extend the common ďparentĒ interface. This is shown earlier in the article with the MyFinancialCommonBusiness interface.

Stateful Session Beans

Letís move on to the other session bean, you need to know for the component developer exam, stateful session beans. In contrast to stateless session beans, stateful session beans maintain conversation state for an individual client over one or more method requests. It is not shared among clients, and the link with the client is maintained until the client ends the session or there is a session timeout. The client state is held in the EJB containerís cache. Of course if the container crashes, then the conversational state will be lost. The key difference between stateless and stateful beans is their lifecycles. The EJB container will ensure that all initial and subsequent method invocations are handled by the same stateful bean instance for the same client. In the figure below is shown the one-to-one mapping between a bean instance and a client enforced behind the scenes by the container.

Tutorial: Review of Session Bean for the Component Developer Exam-a3-clientstatefulsessionbeans.jpg
Figure: Stateful Session Beans interfacing with Clients





It is this one-to-one mapping between a client and a bean instance that makes maintenance of the bean conversational state possible. The downside of this is that stateful session bean instances cannot be pooled and reused while a client session is active. Rather the bean instance must be kept in memory waiting for the next request from the client with which it is linked during the session. The implications of this is that when a container must hold a large number of concurrent clients, the container will have a large memory footprint. In order to better manage this potential problem, EJB containers use an optimization technique called passivation. What this does it to store the state of inactive stateful session beans into storage. Stateful session beans are ideal for online shopping or workflow-oriented business processes.

The TodosBusinessBean

The process of creating a TudoList is a multi-step process creating a TodoList as well as at least one Todo in order to populate the list. Also as the list are being shared it is necessary to keep the conversation state with the bean during the client session. The steps involved are split between two beans, TodoBusinessBean and TodoListBusinessBean. Note that we are only showing the TodoBusinesBean for the sake of brevity. Let us look at the TudoBusiness interface and TudoBusinessBean to illustrate.

Here is the interface:

Java Code: definition of statefull session bean interface
package com.acme.tudo.buslogic;
import javax.ejb.Local;
import com.acme.tudo.persistence.Todo;

@Local
public interface TodosBusiness {

    /**
     * Find a Todo by ID.
     */
    Todo findTodo(String todoId);

    /**
     * Create a new Todo.
     */
    void createTodo(String listId, Todo todo);

    /**
     * Update a Todo.
     */
    void updateTodo(Todo todo);

    /**
     * Delete a Todo.
     */
    void deleteTodo(String todoId);
    
    /**
     * Complete a Todo.
     */
    Todo completeTodo(String todoId);

    /**
     * Re-open a Todo.
     */
    Todo reopenTodo(String todoId);

}
And here is the implementation:

Java Code: implementation of statefull session bean
package com.acme.tudo.buslogic;

import java.util.Calendar;
import java.util.Date;
import javax.ejb.EJB;
import javax.ejb.Stateful;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.acme.tudo.persistence.Todo;
import com.acme.tudo.persistence.TodoList;
import com.acme.tudo.persistence.User;
import com.acme.tudo.persistence.eao.TodoEAO;

@Stateful(name=ĒTudoBusinessĒ)
public class TodosBusinessBean implements TodosBusiness {

    private final Log log = LogFactory.getLog(UserBusinessBean.class);

    @EJB
    private TodoEAO todoEAO;

    @EJB
    private TodoListsBusiness todoListsBusiness;
    
    @EJB
    private UserBusiness userBusiness;

    public TodosBusinessBean () {}

    @Override
    public Todo findTodo(String todoId) {
        if (log.isDebugEnabled()) {
            log.debug("Finding Todo with ID " + todoId);
        }
        Todo todo = todoEAO.getTodo(Integer.getInteger(todoId));
        TodoList todoList = todo.getTodoList();
        User user = userBusiness.getCurrentUser();
        if (!user.getTodoLists().contains(todoList)) {
            if (log.isInfoEnabled()) {
                log.info("Permission denied when finding Todo ID '" + todoId
                        + "' for User '" + user.getLogin() + "'");
            }
            throw new SecurityException(
                    "Permission denied to access this Todo.");           
        }
        return todo;
    }

    @Override
    public void createTodo(String listId, Todo todo) {
        if (log.isDebugEnabled()) {
            log.debug("Creating a new Todo with description "
                    + todo.getDescription());
        }
        Date now = Calendar.getInstance().getTime();
        todo.setCreationDate(now);
        TodoList todoList = todoListsBusiness.findTodoList(listId);
        todo.setTodoList(todoList);
        todoList.getTodos().add(todo);
        todoEAO.saveTodo(todo);
        todoListsBusiness.updateTodoList(todoList);
    }

    @Override
    public void updateTodo(Todo todo) {
        if (log.isDebugEnabled()) {
            log.debug("Update the Todo with id " + todo.getTodoId());
        }
        todoEAO.saveTodo(todo);
        todoListsBusiness.updateTodoList(todo.getTodoList());
    }

    @Override
    public void deleteTodo(String todoId) {
        if (log.isDebugEnabled()) {
            log.debug("Delete the Todo with id " + todoId);
        }
        Todo todo = this.findTodo(todoId);
        TodoList todoList = todo.getTodoList();
        todoList.getTodos().remove(todo);
        todoEAO.removeTodo(Integer.getInteger(todoId));
        todoListsBusiness.updateTodoList(todoList);
    }

    @Override
    public Todo completeTodo(String todoId) {
        Todo todo = this.findTodo(todoId);
        todo.setCompleted(true);
        todo.setCompletionDate(Calendar.getInstance().getTime());
        todoListsBusiness.updateTodoList(todo.getTodoList());
        return todo;
    }

    @Override
    public Todo reopenTodo(String todoId) {
        Todo todo = this.findTodo(todoId);
        todo.setCompleted(false);
        todo.setCompletionDate(null);
        todoListsBusiness.updateTodoList(todo.getTodoList());
        return todo;
    }
}

Letís run through the different aspects of the EJB for TudoBusiness. Similarly to stateless session beans, we have a simple POJO that has been decorated with various annotations and second consistent with session bean programming rules, the TodoBusinessBean has a no-argument constructor. The @Stateful annotation is used to mark the TodoBusinessBean POJO. This annotation behaves similarly to the @Stateless annotation. The bean implements the TodoBusiness local business interface. Letís outline the other rules specific to stateful session beans:
  1. The stateful session bean instance variables must use Java primitives or Serializable variable for storing the conversational state. This is a requirement for passivation.
  2. The stateful session beans must define a business method for removing the bean instance by itís client using the @Remove annotation. This is because it is not possible to pool and reuse stateful beans.
  3. The stateful session beans can use the following lifecycle callback methods: 1. @PostConstruct; 2. @PreDestroy; 3. @PrePassivate and 4. @PostActivate
Youíll see these rules applied when we explore a concrete stateful session beans example next. Although this bean also uses an EAO rather than directly using JDBC, I am posting below an example of what the bean would look like if it used JDBC directly. The purpose of this is to show how the lifecycle callback methods would be used in this situation.

Java Code: jdbc version of statefull session bean implementation
package com.acme.tudo.buslogic;

import java.util.Calendar;
import java.util.Date;
import javax.ejb.EJB;
import javax.ejb.Stateful;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.acme.tudo.persistence.Todo;
import com.acme.tudo.persistence.TodoList;
import com.acme.tudo.persistence.User;
import com.acme.tudo.persistence.eao.TodoEAO;

@Stateful(name=ĒTudoBusinessĒ)
public class TodosBusinessBean implements TodosBusiness {

    private final Log log = LogFactory.getLog(TodosBusinessBean.class);

    @Resource(name = "jdbc/tudoDS", mappedName = "java:/tudoDS")
    private DataSource dataSource;

    private Connection connection;

    @EJB
    private TodoListsBusiness todoListsBusiness;
    
    @EJB
    private UserBusiness userBusiness;

    public TodosBusinessBean () {}

    @PostConstruct
    @PostActivate
    public void openConnection() {
        try {
            connection = dataSource.getConnection();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        }
    }


    @Override
    public Todo findTodo(String todoId) {
        if (log.isDebugEnabled()) {
            log.debug("Finding Todo with ID " + todoId);
        }
        Todo todo = todoEAO.getTodo(Integer.getInteger(todoId));
        TodoList todoList = todo.getTodoList();
        User user = userBusiness.getCurrentUser();
        if (!user.getTodoLists().contains(todoList)) {
            if (log.isInfoEnabled()) {
                log.info("Permission denied when finding Todo ID '" + todoId
                        + "' for User '" + user.getLogin() + "'");
            }
            throw new SecurityException(
                    "Permission denied to access this Todo.");           
        }
        return todo;
    }

    @Override
    public void createTodo(String listId, Todo todo) {
        if (log.isDebugEnabled()) {
            log.debug("Creating a new Todo with description "
                    + todo.getDescription());
        }
        Date now = Calendar.getInstance().getTime();
        todo.setCreationDate(now);
        TodoList todoList = todoListsBusiness.findTodoList(listId);
        todo.setTodoList(todoList);
        todoList.getTodos().add(todo);
        todoEAO.saveTodo(todo);
        todoListsBusiness.updateTodoList(todoList);
    }

...

    @Override
    public Todo completeTodo(String todoId) {
        Todo todo = this.findTodo(todoId);
        todo.setCompleted(true);
        todo.setCompletionDate(Calendar.getInstance().getTime());
        todoListsBusiness.updateTodoList(todo.getTodoList());
        return todo;
    }

    @Override
    public Todo reopenTodo(String todoId) {
        Todo todo = this.findTodo(todoId);
        todo.setCompleted(false);
        todo.setCompletionDate(null);
        todoListsBusiness.updateTodoList(todo.getTodoList());
        return todo;
    }

    @Remove
    public void cancelTodoCreation() {
    }

    @Remove
    public void createTudo(String listId, Todo todo) {

        Date now = Calendar.getInstance().getTime();
        todo.setCreationDate(now);
        TodoList todoList = todoListsBusiness.findTodoList(listId);
        todo.setTodoList(todoList);
        todoList.getTodos().add(todo);
        try {
            Statement statement = connection.createStatement();
            String sql = "INSERT INTO TODOS (" + "id, " + "creation_date, "
                    + "description, " + "priority, " + "completed, "
                    + "completion_date, " + "todo_list_id" + "due_date"                     +") VALUES (" + "'"
                    + todo.getTodoId() + "', " + "'"
                    + todo getCreationDate() + "', " + "'"
                    + todo.getDescription() + "', " + "'"
                    + todo.getPriority() + "', " + "'"
                    + todo.getCompleted() + "', " + "'"
                    + todo.getCompletionDate() + "', " + "'"
                    ...
                    + todo.getDueDate() + "'" + ")";
            statement.execute(sql);
            statement.close();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        }
    }

    @PrePassivate
    @PreDestroy
    public void cleanup() {
        try {
            connection.close();
            connection = null;
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        }
    }
}
Stateful Session Bean Lifecycle

As was shown in the previous article, Tutorial: In Depth View of EJB Bean for Component Developer Exam, the lifecycle of the stateful session bean is the following:
  1. The SSB is instantiated
  2. The EJB container injects the beanís SessionContext if required
  3. The EJB container performs any other dependency injection needed by any other the beanís metadata
  4. The EJB container invokes a PostConstruct callback method if it is present in the bean
In addition to the PostConstruct event and when the PreDestroy event similar to a stateless session bean, there are two other callback events for which are called PrePassivate and PostActivate. They are related to the passivation and activation of a which are part of the passivation and activation process respectively. This is shown in the JDBC version of TodoBusinessBean. In this version a JDBC data source is injected using the @Resource annotation. Both the PostConstruct D and PostPassivate E callbacks prepare the bean for use by opening a database connection from the injected data source. On the other hand, both the @PrePassivate and @PreDestroy callbacks are used to close the cached JDBC connection. If the bean had instance variables that were stored in the client conversational state across business method calls, the data would be maintained across each step in the TodoList and Todo creation process. When the workflow is terminated, the client can then invoke the method annotated with @Remove.

Transactions

As was mentioned earlier in this article if you have a bean managed transaction with stateful session beans, the transaction can span two or more methods. This is only allowed with stateful session beans since there is a one to one relation between the bean and the client.

Multiple Interfaces

Stateful session beans will support both local and remote invocation through the @Local and @Remote annotations. One thing it will not support however is being part of a web service endpoint interface due to the fact that SOAP-based web services are inherently stateless. Finally remember that you should include at least one @Remove annotated method in your stateful beanís business interface for cleaning up instance variables.

Session bean clients

Similar to a stateless session bean, almost any Java component can be client to a session bean. POJOs, servlets, JSPs, or other EJBs can access session beans. In fact, stateless session beans exposed through web services endpoints can even be accessed by non-Java clients such as .NET applications.

In EJB 3 accessing remote or local session beans is done in almost exactly the same manner. From a client perspective , the pattern used doesnít appear to be different unless you look under the covers. The general steps to use a session bean are the following:

  • The client gets a reference to the beans either directly or indirectly via JNDI.
  • The session bean invocations need to be made through the appropriate interface for the access type.
  • The client must make the necessary method calls to complete the business task.
  • For clients to a stateful session bean, the last client invocation should be to the method annotated as a remove method.

Best Practices for Session Beans

To finish up, I will provide you with a list of session bean best practices that will serve you well for the component developer exam. They are the following:
  • Always choose the bean type appropriate for the business task. If you need to maintain conversation state during a long running business process use a stateful session bean otherwise stateless session beans will be suitable most of the time. Always be aware of the memory impact of using stateful session beans
  • Determine carefully the appropriate interface types for session beans. Remote interfaces will cause a hit on the performance of your application. If your client can run in the same JVM as the bean, then use a local interface.
  • When youíre using dependency injection, avoid injecting different type of beans into each other. You obviously donít want to inject a stateful session bean into a stateless session bean or servlet. Especially as they will be stored as instance variables and available globally for subsequent clients even after the stateless bean instance is returned to the pool.
  • Isolate crosscutting concerns (i.e. logging, auditing, etc) from the business logic which will be directly implemented in the session bean. Use business interceptors for implementing such aspects of the application.
  • Be wary of the kind of data you are storing in the conversation state. Use primitive instance variables in a stateful bean whenever possible rather than composite objects.
  • Remember to define remove methods in a stateful session bean.
  • For stateful session beans, tweak the configuration for passivation and timeouts in order to optimize your application.
OK. Thatís it. In the next article we will cover Message Driven Beans.