Chapter 3. Building business logic with session beans – EJB 3 in Action

Chapter 3. Building business logic with session beans

This chapter covers

  • Development of stateless and stateful session beans
  • Session bean lifecycle
  • Session bean clients
  • Session bean performance considerations and best practices

At the heart of any enterprise application lies its business logic. In an ideal world, application developers should only be concerned with defining and implementing the business logic, while concerns like presentation, persistence, or integration should largely be window dressing. From this perspective, session beans are the most important part of the EJB technology because their purpose in life is to model high-level business processes.

If you think of a business system as a horse-drawn chariot with a driver carrying the Greco-Roman champion to battle, session beans are the driver. Session beans utilize data and system resources (the chariot and the horses) to implement the goals of the user (the champion) using business logic (the skills and judgment of the driver). For this and other reasons, sessions beans, particularly stateless session beans, have been popular, even despite the problems of EJB 2. EJB 3 makes this vital bean type a lot easier to use.

In chapter 1 we briefly introduced session beans. In chapter 2 we saw simple examples of these beans in action. In this chapter, we’ll discuss session beans in much greater detail, focusing on their purpose, the different types of session beans, how to develop them, and some of the advanced session bean features available to you.

We start this chapter by exploring some basic session bean concepts, and then discuss some fundamental characteristics of session beans. We then cover each type—stateful and stateless—in detail before introducing bean client code. Finally, we examine session bean best practices at the end of the chapter.

3.1. Getting to know session beans

A typical enterprise application will have numerous business activities or processes. For example, our ActionBazaar application has processes such as creating a user, adding an item for auctioning, bidding for an item, ordering an item, and many more. Session beans can be used to encapsulate the business logic for all such processes.

The theory behind session beans centers on the idea that each request by a client to complete a distinct business process is completed in a session. So what is a session? If you have used a Unix server you may have used Telnet to connect to the server from a PC client. Telnet allows you to establish a login session with the Unix server for a finite amount of time. During this session you may execute several commands in the server. Simply put, a session is a connection between a client and a server that lasts for a finite period of time.

A session may either be very short-lived, like an HTTP request, or span a long time, like a login session when you Telnet or FTP into a Unix server. Similar to a typical Telnet session, a bean may maintain its state between calls, in which case it is stateful, or it may be a one-time call, in which case it’s stateless. A typical example of a stateful application is the module that a bidder uses to register himself in the ActionBazaar application. That process takes place in multiple steps. An example of a stateless business module is the application code that is used to place a bid for an item. Information, such as user ID, item number, and amount, is passed in and success or failure is returned. This happens all in one step. We’ll examine the differences between stateless and stateful session beans more closely in section 3.1.4.

As you might recall, session beans are the only EJB components that are invoked directly by clients. A client can be anything, such as a web application component (servlet, JSP, JSF, and so on), a command-line application, or a Swing GUI desktop application. A client can even be a Microsoft .NET application using web services access.

At this point you might be wondering what makes session beans special. After all, why use a session bean simply to act as a business logic holder? Glad that you asked. Before you invest more of your time, let’s address this question first. Then we’ll show you the basic anatomy of a session bean and explore the rules that govern it before examining the differences between stateless and stateful session beans.

3.1.1. Why use session beans?

Session beans are a lot more than just business logic holders. Remember the EJB services we briefly mentioned in chapter 1? The majority of those services are specifically geared toward session beans. They make developing a robust, feature-rich, impressive business logic tier remarkably easy (and maybe even a little fun). Let’s take a look at some of the most important of these services.

Concurrency and thread safety

The whole point of building server-side applications is that they can be shared by a large number of remote clients at the same time. Because session beans are specifically meant to handle client requests, they must support a high degree of concurrency safely and robustly. In our ActionBazaar example, it is likely thousands of concurrent users will be using the PlaceBid session bean we introduced in chapter 2. The container employs a number of techniques to “automagically” make sure you don’t have to worry about concurrency or thread safety. This means that we can develop session beans as though we were writing a standalone desktop application used by a single user. You’ll learn more about these “automagic” techniques, including pooling, session management, and passivation, later in this chapter.

Remoting and web services

Session beans support both Java Remote Method Invocation (RMI)-based native and Simple Object Access Protocol (SOAP)-based web services remote access. Other than some minor configuration, no work is required to make session bean business logic accessible remotely using either method. This goes a long way toward enabling distributed computing and interoperability. You’ll see session bean remoteability in action in just a few sections.

Transaction and security management

Transactions and security management are two enterprise-computing mainstays. Session beans, with their pure configuration-based transactions, authorization, and authentication, make supporting these requirements all but a nonissue. We won’t discuss these services in this chapter, but chapter 6 is devoted to EJB transaction management and security.

Timer services and interceptors

Interceptors are EJB’s version of lightweight aspect-oriented programming (AOP). Recall that AOP is the ability to isolate “crosscutting” concerns into their own modules and apply them across the application through configuration. Crosscutting concerns include things like auditing and logging that are repeated across an application but are not directly related to business logic. We’ll discuss interceptors in great detail in chapter 5.

Timer services are EJB’s version of lightweight application schedulers. In most medium- to large-scale applications, you’ll find that you need some kind of scheduling services. In ActionBazaar, scheduled tasks could be used to monitor when the bidding for a particular item ends and determine who won an auction. Timer services allow us to easily turn a session bean into a recurring or nonrecurring scheduled task. We’ll save the discussion of timer services for chapter 5 as well.

Now that you are convinced you should use session beans, let’s look at some of their basic characteristics.


A session bean alternative: Spring

Clearly, EJB 3 session beans are not your only option in developing your application’s business tier. POJOs managed by lightweight containers such as Spring could also be used to build the business logic tier. Before jumping on either the EJB 3 session bean or Spring bandwagon, think about what your needs are.

If your application needs robust support for accessing remote components or the ability to seamlessly expose your business logic as web services, EJB 3 is the clear choice. Spring also lacks good equivalents of instance pooling, automated session state maintenance, and passivation/activation. Because of heavy use of annotations, you can pretty much avoid “XML Hell” using EJB 3; the same cannot be said of Spring. Moreover, because it is an integral part of the Java EE standard, the EJB container is natively integrated with components such as JSF, JSP, servlets, the JTA transaction manager, JMS providers, and Java Authentication and Authorization Service (JAAS) security providers of your application server. With Spring, you have to worry whether your application server fully supports the framework with these native components and other high-performance features like clustering, load balancing, and failover.

If you aren’t worried about such things, then Spring is not a bad choice at all and even offers a few strengths of its own. The framework provides numerous simple, elegant utilities for performing many common tasks such as the JdbcTemplate and JmsTemplate. If you plan to use dependency injection with regular Java classes, Spring is great since DI only works for container components in EJB 3. Also, Spring AOP or AspectJ is a much more feature-rich (albeit slightly more complex) choice than EJB 3 interceptors.

Nevertheless, if portability, standardization, and vendor support are important to you, EJB 3 may be the way to go. EJB 3 is a mature product that is the organic (though imperfect) result of the incremental effort, pooled resources, shared ownership, and measured consensus of numerous groups of people. This includes the grassroots Java Community Process (JCP); some of the world’s most revered commercial technology powerhouses like IBM, Sun, Oracle, and BEA; and spirited open-source organizations like Apache and JBoss.


3.1.2. Session beans: the basics

Although we briefly touched on session beans in the previous chapter, we didn’t go into great detail about developing them. Before we dive in, let’s revisit the code in chapter 2 to closely examine some basic traits shared by all session beans.

The anatomy of a session bean

Each session bean implementation has two distinct parts—one or more bean interfaces and a bean implementation class. In the PlaceBid bean example from chapter 2, the bean implementation consisted of the PlaceBid interface and the PlaceBidBean class, as shown in figure 3.1.

Figure 3.1. Parts of the PlaceBid session bean. Each session bean has one or more interfaces and one implementation class.

All session beans must be divided into these two parts. This is because clients cannot have access to the bean implementation class directly. Instead, they must use session beans through a business interface. Nonetheless, interface-based programming is a sound idea anyway, especially when using dependency injection.

Interface-based programming is the practice of not using implementation classes directly whenever possible. This approach promotes loose coupling since implementation classes can easily be swapped out without a lot of code changes. EJB has been a major catalyst in the popularization of interface-based programming; even the earliest versions of EJB followed this paradigm, later to form the basis of DI.

The session bean business interface

An interface through which a client invokes the bean is called a business interface. This interface essentially defines the bean methods appropriate for access through a specific access mechanism. For example, let’s revisit the PlaceBid interface in chapter 2:

@Local
public interface PlaceBid {
Bid addBid(Bid bid);
}

Since all EJB interfaces are POJIs, there isn’t anything too remarkable in this code other than the @Local annotation specifying that it’s a local interface. Recall that a business interface can be remote or even web service-accessible instead. We’ll talk more about the three types of interfaces in section 3.2.3. The interesting thing to note right now is the fact that a single EJB can have multiple interfaces. In other words, EJB implementation classes can be polymorphic, meaning that different clients using different interfaces could use them in completely different ways.

The EJB bean class

Just like typical OO programming, each interface that the bean intends to support must be explicitly included in the bean implementation class’s implements clause. We can see this in the code for the PlaceBidBean from chapter 2:

@Stateless
public class PlaceBidBean implements PlaceBid {
...
public PlaceBidBean() {}

public Bid addBid(Bid bid) {
System.out.println("Adding bid, bidder ID=" + bid.getBidderID()
+ ", item ID=" + bid.getItemID() + ", bid amount="
+ bid.getBidAmount() + ".");

return save(bid);
}
...
}

The PlaceBidBean class provides the concrete implementation of the addBid method required by the PlaceBid interface. Session bean implementation classes can never be abstract, which means that all methods mandated by declared business interfaces must be implemented in the class.

Note that EJB implementation classes can have nonprivate methods that are not accessible through any interface. Such methods can be useful for creating clever unit-testing frameworks and while implementing lifecycle callback, as you’ll learn in section 3.2.5. Also, an EJB bean class can make use of OO inheritance. You could use this strategy to support a custom framework for your application. For example, you could put commonly used logic in a parent POJO class that a set of beans inherits from.


Unit-testing your session beans

It is clear that session beans are POJOs. Since EJB annotations are ignored by the JVM, session beans can be unit-tested using a framework like JUnit or TestNG without having to deploy them into an EJB container. For more information on JUnit, browse www.junit.org.

On the other hand, since several container-provided services such as dependency injection cannot be used outside the container, you cannot perform functional testing of applications using EJBs outside the container—at least not easily.


Now that we’ve looked at the basic structure of session beans, we’ll outline relatively simple programming rules for a session bean.

3.1.3. Understanding the programming rules

Like all EJB 3 beans, session beans are POJOs that follow a small set of rules. The following summarizes the rules that apply to all types of session beans:

  • As we discussed earlier in section 3.1.2, a session bean must have at least one business interface.
  • The session bean class must be concrete. You cannot define a session bean class as either final or abstract since the container needs to manipulate it.
  • You must have a no-argument constructor in the bean class. As we saw, this is because the container invokes this constructor to create a bean instance when a client invokes an EJB. Note that the compiler inserts a default no-argument constructor if there is no constructor in a Java class.
  • A session bean class can subclass another session bean or any other POJO. For example, a stateless session bean named BidManager can extend another session bean PlaceBidBean in the following way:
    @Stateless
    public BidManagerBean extends PlaceBidBean implements BidManager {
    ...
    }
  • The business methods and lifecycle callback methods may be defined either in the bean class or in a superclass. It’s worth mentioning here that annotation inheritance is supported with several limitations with EJB 3 session beans. For example, the bean type annotation @Stateless or @Stateful specified in the PlaceBidBean superclass will be ignored when you deploy the BidManagerBean. However, any annotations in the superclasses used to define lifecycle callback methods (more about that later in this section) and resource injections will be inherited by the bean class.
  • Business method names must not start with “ejb.” For example, avoid a method name like ejbCreate or ejbAddBid because it may interfere with EJB infrastructure processing. You must define all business methods as public, but not final or static. If you are exposing a method in a remote business interface of the EJB, then make sure that the arguments and the return type of the method implement the java.io.Serializable interface.

You’ll see these rules applied when we explore concrete examples of stateless and stateful session beans in sections 3.2 and 3.3, respectively.

Now that we’ve looked at the basic programming rules for the session beans, let’s discuss the fundamental reasons behind splitting them into two groups.

3.1.4. Conversational state and session bean types

Earlier, we talked about stateful and stateless session beans. However, we have so far avoided the real differences between them. This grouping of bean types centers on the concept of the conversational state.

A particular business process may involve more than one session bean method call. During these method calls, the session bean may or may not maintain a conversational state. This terminology will make more sense if you think of each session bean method call as a “conversation,” or “exchange of information,” between the client and the bean. A bean that maintains conversational state “remembers” the results of previous exchanges, and is a stateful session bean. In Java terms, this means that the bean will store data from a method call into instance variables and use the cached data to process the next method call. Stateless session beans don’t maintain any state. In general, stateful session beans tend to model multistep workflows, while stateless session beans tend to model general-purpose, utility services used by the client.

The classic example of maintaining conversational state is the e-commerce website shopping cart. When the client adds, removes, modifies, or checks out items from the shopping cart, the shopping cart is expected to store all the items that were put into it while the client was shopping. As you can imagine, except for the most complex business processes in an application, most session bean interactions don’t require a conversational state. Putting in a bid at ActionBazaar, leaving buyer or seller feedback, and viewing a particular item for bid are all examples of stateless business processes.

As you’ll soon see, however, this does not mean that stateless session beans cannot have instance variables. Even before we explore any code, common sense should tell us that session beans must cache some resources, like database connections, for performance reasons. The critical distinction here is client expectations. As long as the client does not need to depend on the fact that a session bean uses instance variables to maintain conversational state, there is no need to use a stateful session bean.

3.1.5. Bean lifecycle callbacks

A session bean has a lifecycle. This mean that beans go through a predefined set of state transitions. If you’ve used Spring or EJB 2, this should come as no surprise. If you haven’t, the concept can be a little tricky to grasp.

To understand the bean lifecycle, it is important to revisit the concept of managed resources. Recall that the container manages almost every aspect of session beans. This means that neither the client nor the bean is responsible for determining when bean instances are created, when dependencies are injected, when bean instances are destroyed, or when to take optimization measures. Managing these actions enables the container to provide the abstractions that constitute some of the real value of using EJBs, including DI, automated transaction management, AOP, transparent security management, and so on.

The lifecycle events

The lifecycle of a session bean may be categorized into several phases or events. The most obvious two events of a bean lifecycle are creation and destruction. All EJBs go through these two phases. In addition, stateful session beans go through the passivation/activation cycle, which we discuss in depth in section 3.3.5. Here, we take a close look at the phases shared by all session beans: creation and destruction.

The lifecycle for a session bean starts when a bean instance is created. This typically happens when a client receives a reference to the bean either by doing a JNDI lookup or by using dependency injection. The following steps occur when a bean is initialized:

  1. The container invokes the newInstance method on the bean object. This essentially translates to a constructor invocation on the bean implementation class.
  2. If the bean uses DI, all dependencies on resources, other beans, and environment components are injected into the newly created bean instance.

Figure 3.2 depicts this series of events.

Figure 3.2. The lifecycle of an EJB starts when a method is invoked. The container creates a bean instance and then dependencies on resources are injected. The instance is then ready for method invocation.

After the container determines that an instance is no longer needed, the instance is destroyed. This sounds just fine until you realize that the bean might need to know when some of its lifecycle transitions happen. For example, suppose that the resource being injected into a bean is a JDBC data source. That means that it would be nice to be able to know when it is injected so you can open the JDBC database connection to be used in the next business method invocation. In a similar way, the bean would also need to be notified before it is destroyed so that the open database connection can be properly closed.

This is where callbacks come in.

Understanding lifecycle callbacks

Lifecycle callbacks are bean methods (not exposed by a business interface) that the container calls to notify the bean about a lifecycle transition, or event. When the event occurs, the container invokes the corresponding callback method, and you can use these methods to perform business logic or operations such as initialization and cleanup of resources.

Callback methods are bean methods that are marked with metadata annotations such as @PostContruct and @PreDestroy. They can be public, private, protected, or package-protected. As you might have already guessed, a Post-Construct callback is invoked just after a bean instance is created and dependencies are injected. A PreDestroy callback is invoked just before the bean is destroyed and is helpful for cleaning up resources used by the bean.

While all session beans have PostConstruct and PreDestroy lifecycle events, stateful session beans have two additional ones: PrePassivate and PostActivate. Since stateful session beans maintain state, there is a stateful session bean instance for each client, and there could be many instances of a stateful session bean in the container. If this happens, the container may decide to deactivate a stateful bean instance temporarily when not in use; this process is called passivation. The container activates the bean instance again when the client needs it; this process is called activation. The @PrePassivate and @PostActivate annotations apply to the passivation and activation lifecycle events.


Note

You can define a lifecycle callback method either in the bean class or in a separate interceptor class.


Table 3.1 lists the lifecycle callback method annotations, where they are applied, and what the callback methods are typically used for.

Table 3.1. Lifecycle callbacks are created to handle lifecycle events for an EJB. You can create these callback methods either in the bean class or in an external interceptor class.

Callback Annotation

Type of EJB

Typically Used For...

javax.annotation. PostConstruct

Stateless, stateful, MDB

This annotated method is invoked after a bean instance is created and dependency injection is complete. Generally this callback is used to initialize resources (for example, opening database connections).

javax.annotation. PreDestroy

Stateless, stateful, MDB

This annotated method is invoked prior to a bean instance being destroyed. Generally this callback is used to clean up resources (for example, closing database connections).

javax.ejb.PrePassivate

Stateful

This annotated method is invoked prior to a bean instance being passivated. Generally this callback is used to clean up resources, such as database connections, TCP/IP sockets, or any resources that cannot be serialized during passivation.

javax.ejb.PostActivate

Stateful

This annotated method is invoked after a bean instance is activated. Generally this callback is used to restore resources, such as database connections that you cleaned up in the Pre-Passivate method.

In sections 3.2.4 and 3.3.4, you’ll learn how to define lifecycle callback methods in the bean class for stateless and stateful beans. We’ll defer our discussion of lifecycle callback methods in the interceptor classes to chapter 5.

At this point, let’s launch our detailed exploration with the simpler stateless session bean model and save stateful session beans for later.

3.2. Stateless session beans

As noted earlier, stateless session beans model tasks don’t maintain conversational state. This means that session beans model tasks can be completed in a single method call, such as placing a bid. However, this does not mean that all stateless session beans contain a single method, as is the case for the PlaceBid-Bean in chapter 2. In fact, real-world stateless session beans often contain several closely related business methods, like the BidManager bean we’ll introduce soon. By and large, stateless session beans are the most popular kind of session beans. They are also the most performance efficient. To understand why, take a look at figure 3.3, which shows a high-level schematic of how stateless session beans are typically used by clients.

Figure 3.3. Stateless session bean instances can be pooled and may be shared between clients. When a client invokes a method in a stateless session bean, the container either creates a new instance in the bean pool for the client or assigns one from the bean pool. The instance is returned to the pool after use.

As you’ll learn in section 3.2.4, stateless beans are pooled. This means that for each managed bean, the container keeps a certain number of instances handy in a pool. For each client request, an instance from the pool is quickly assigned to the client. When the client request finishes, the instance is returned to the pool for reuse. This means that a small number of bean instances can service a relatively large number of clients.

In this section you’ll learn more about developing stateless session beans. We’ll develop part of the business logic of our ActionBazaar system using a stateless session to illustrate its use. You’ll learn how to use @Stateless annotations as well as various types of business interfaces and lifecycle callbacks supported with stateless session beans.

Before we jump into analyzing code, let’s briefly discuss the ActionBazaar business logic that we’ll implement as a stateless session bean.

3.2.1. The BidManagerBean example

Bidding is a critical part of the ActionBazaar functionality. Users can bid on an item and view the current bids, while ActionBazaar administrators and customer service representatives can remove bids under certain circumstances. Figure 3.4 depicts these bid-related actions.

Figure 3.4. Some ActionBazaar bid-related actions. While bidders can place bids and view the current bids on an item, admins can remove bids when needed. All of these actions can be modeled with a singe stateless session bean.

Because all of these bid-related functions are simple, single-step processes, a stateless session bean can be used to model all of them. The BidManagerBean presented in listing 3.1 contains methods for adding, viewing, and canceling (or removing) bids. This is essentially an enhanced, more realistic version of the basic PlaceBid EJB we saw earlier. The complete code is available for download from www.manning.com/panda in the zip containing code examples.


Note

We are using JDBC for simplicity only because we have not introduced the EJB 3 Java Persistence API (JPA) in any detail quite yet, and we don’t assume you already understand ORM. Using JDBC also happens to demonstrate the usage of dependency injection of resources and the stateless bean lifecycle callbacks pretty nicely! In general, you should avoid using JDBC in favor of JPA once you are comfortable with it.


Listing 3.1. Stateless session bean example

As you’ve seen before, the @Stateless annotation marks the POJO as a stateless session bean . The BidManagerBean class implements the BidManager interface, which is marked @Remote . We use the @Resource annotation to perform injection of a JDBC data source . The BidManagerBean has a no-argument constructor that the container will use to create instances of BidManagerBean EJB object. The PostConstruct and PreDestroy callbacks are used to manage a JDBC database connection derived from the injected data source. Finally, the addBid business method adds a bid into the database.

We’ll start exploring the features of EJB 3 stateless session beans by analyzing this code next, starting with the @Stateless annotation.

3.2.2. Using the @Stateless annotation

The @Stateless annotation marks the BidManagerBean POJO as a stateless session bean. Believe it or not, other than marking a POJO for the purposes of making the container aware of its purpose, the annotation does not do much else. The specification of the @Stateless annotation is as follows:

@Target(TYPE) @Retention(RUNTIME)
public @interface Stateless {
String name() default "";
String mappedName() default "";
String description() default "";

}

The single parameter, name, specifies the name of the bean. Some containers use this parameter to bind the EJB to the global JNDI tree. Recall that JNDI is essentially the application server’s managed resource registry. All EJBs automatically get bound to JNDI as soon as they catch the container’s watchful eye. You’ll see the name parameter in use again in chapter 11 when we discuss deployment descriptors. In listing 3.1, the bean name is specified as BidManager. As the annotation definition shows, the name parameter is optional since it is defaulted to an empty String. We could easily omit it as follows:

@Stateless
public class BidManagerBean implements BidManager {

If the name parameter is omitted, the container assigns the name of the class to the bean. In this case, the container assumes the bean name is BidManagerBean. mappedName is a vendor-specific name that you can assign to your EJB; some containers, such as the GlassFish application server, use this name to assign the global JNDI name for the EJB. As we noted, the BidManagerBean implements a business interface named BidManager. Although we’ve touched on the idea of a business interface, we haven’t dug very deeply into the concept. This is a great time to do exactly that.

3.2.3. Specifying bean business interfaces

In section 3.1, we introduced you to EJB interfaces. Now let’s explore a bit more how they work with stateless session beans. Client applications can invoke a stateless session bean in three different ways. In addition to local invocation within the same JVM and remote invocation through RMI, stateless beans can be invoked remotely as web services.

Three types of business interfaces correspond to the different access types; each is identified through a distinct annotation. Let’s take a detailed look at these annotations.

Local interface

A local interface is designed for clients of stateless session beans collocated in the same container (JVM) instance. You designate an interface as a local business interface by using the @Local annotation. The following could be a local interface for the BidManagerBean class in listing 3.1:

@Local
public interface BidManagerLocal {
void addBid(Bid bid);
void cancelBid(Bid bid);
List<Bid> getBids(Item item);
}

Local interfaces don’t require any special measures in terms of either defining or implementing them.

Remote interface

Clients residing outside the EJB container’s JVM instance must use some kind of remote interface. If the client is also written in Java, the most logical and resource-efficient choice for remote EJB access is Java Remote Method Invocation (RMI). In case you are unfamiliar with RMI, we provide a brief introduction to RMI in appendix A. For now, all you need to know is that 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. EJB 3 enables a stateless bean to be made accessible via RMI through the @Remote annotation. The BidManager business interface in our example uses the annotation to make the bean remotely accessible:

@Remote
public interface BidManager extends Remote {
...
}

A remote business interface may extend java.rmi.Remote as we’ve done here, although this is optional. Typically the container will perform byte-code enhancements during deployment to extend java.rmi.Remote if your bean interface does not extend it. Remote business interface methods are not required to throw java.rmi.RemoteException unless the business interface extends the java.rmi. Remote interface. Remote business interfaces do have one special requirement: all parameters and return types of interface methods must be 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 specific to stateless session beans that you haven’t seen yet: the web service endpoint interface (also known as SEI). The ability to expose a stateless session bean as a SOAP-based web service is one of the most powerful features of EJB 3. All you need to do to make a bean SOAP accessible is mark a business interface with the @javax.jws.WebService annotation. The following defines a simple web service endpoint interface for the BidManagerBean:

@WebService
public interface BidManagerWS {
void addBid(Bid bid);
List<Bid> getBids(Item item);
}

Note we have omitted the cancelBid bean method from the interface; we don’t want this functionality to be accessible via a web service, although it is accessible locally as well as remotely through RMI. The @WebService annotation doesn’t place any special restrictions on either the interface or the implementing bean. We discuss EJB web services in greater detail in chapter 15.

Working with multiple business interfaces

Although it is tempting, you cannot mark the same interface with more than one access type annotation. For example, you cannot mark the BidManager interface in listing 3.1 with both the @Local and @Remote annotations instead of creating separate BidManagerLocal (local) and BidManager (remote) interfaces, although both interfaces expose the exact same bean methods.

However, a business interface can extend another interface, and you can remove code duplication by creating a business interface that has common methods and business interfaces that extend the common “parent” interface. For example, you can create a set of interfaces utilizing OO inheritance as follows:

public interface BidManager{
void addBid(Bid bid);
List<Bid> getBids(Item item);
}

@Local
public interface BidManagerLocal extends BidManager {
void cancelBid(Bid bid);
}

@Remote
public interface BidManagerRemote extends BidManagerLocal {
}

@WebService
public interface BidManagerWS extends BidManager {
}

If you want, you can apply the @Local, @Remote, or @WebService annotation in the bean class without having to implement the business interface as follows:

@Remote(BidManager.class)
@Stateless
public class BidManagerBean {
...
}

The preceding code marks the BidManager interface as remote through the bean class itself. This way, if you change your mind later, all you’d have to do is change the access type specification in the bean class without ever touching the interface.

Next, we move on to discussing the EJB lifecycle in our example.

3.2.4. Using bean lifecycle callbacks

We introduced you to lifecycle callback methods, or callbacks, earlier in the chapter; now let’s take a deeper look at how they are used with stateless session beans. As far as EJB lifecycles go, stateless session beans have a simple one, as depicted in figure 3.5. In effect, the container does the following:

  1. Creates bean instances using the default constructor as needed.
  2. Injects resources such as database connections.
  3. Puts instances in a managed pool.
  4. Pulls an idle bean out of the pool when an invocation request is received from the client (the container may have to increase the pool size at this point).
  5. Executes the requested business method invoked through the business interface by the client.
  6. When the business method finishes executing, pushes the bean back into the “method-ready” pool.
  7. As needed, retires (a.k.a. destroys) beans from the pool.
Figure 3.5. The chicken or the egg—the stateless session bean lifecycle has three states: does not exist, idle, or busy. As a result, there are only two lifecycle callbacks corresponding to bean creation and destruction.

An important point to note from the stateless session bean lifecycle is that since beans are allocated from and returned to the pool on a per-invocation basis, stateless session beans are extremely performance friendly and a relatively small number of bean instances can handle a large number of virtually concurrent clients.

As you know, there are two types of stateless session bean lifecycle callback methods: (1) callbacks that are invoked when the PostConstruct event occurs immediately after a bean instance is created and set up, and all the resources are injected; and (2) callbacks that are invoked when the PreDestroy event occurs, right before the bean instance is retired and removed from the pool. Note that you can have multiple PostConstruct and PreDestroy callbacks for a given bean (although this is seldom used) in a class or in a separate interceptor class (discussed in chapter 5).

In listing 3.1, the lifecycle callback methods embedded in the bean are initialize and cleanup. Callbacks must follow the pattern of void <METHOD>(). Unlike business methods, callbacks cannot throw checked exceptions (any exception that doesn’t have java.lang.RuntimeException as a parent).

Typically, these callbacks are used for allocating and releasing injected resources that are used by the business methods, which is exactly what we do in our example of BidManagerBean in listing 3.1. In listing 3.1 we open and close connections to the database using an injected JDBC data source.

Recall that the addBid method in listing 3.1 inserted the new bid submitted by the user. The method created a java.sql.Statement from an open JDBC connection and used the statement to insert a record into the BIDS table. The JDBC connection object used to create the statement is a classic heavy-duty resource. It is expensive to open and should be shared across calls whenever possible. It can hold a number of native resources, so it is important to close the JDBC connection when it is no longer needed. We accomplish both these goals using callbacks as well as resource injection.

In listing 3.1, the JDBC data source from which the connection is created is injected using the @Resource annotation. We explore injecting resources using the @Resource annotation in chapter 5; for now, this is all that you need to know.

Let’s take a closer look at how we used the callbacks in listing 3.1.

PostConstruct callback

The setDataSource method saves the injected data source in an instance variable. After injecting all resources, the container checks whether there are any designated PostConstruct methods that need to be invoked before the bean instance is put into the pool. In our case, we mark the initialize method in listing 3.1 with the @PostConstruct annotation:

@PostConstruct
public void initialize() {
...
connection = dataSource.getConnection();
...
}

In the initialize method, we create a java.sql.Connection from the injected data source and save it into the connection instance variable used in addBid each time the client invokes the method.

PreDestroy callback

At some point the container decides that our bean should be removed from the pool and destroyed (perhaps at server shutdown). The PreDestroy callback gives us a chance to cleanly tear down bean resources before this is done. In the cleanup method marked with the @PreDestroy annotation in listing 3.1, we tear down the open database connection resource before the container retires our bean:

@PreDestroy
public void cleanup() {
...
connection.close();
connection = null;
...
}

Since bean instances from the pool are assigned randomly for each method invocation, trying to store client-specific state across method invocations is useless since the same bean instance may not be used for subsequent calls by the same client. On the other hand, stateful session beans, which we’ll discuss next, are ideally suited for this situation.

3.3. Stateful session beans

Stateful session beans are guaranteed to maintain conversational state. They are not programmatically very different from their stateless cousins: as a matter of fact, the only real difference between stateless and stateful beans is how the container manages their lifecycle. Unlike with stateless beans, the container makes sure that subsequent method invocations by the same client are handled by the same stateful bean instance. Figure 3.6 shows the one-to-one mapping between a bean instance and a client enforced behind the scenes by the container. As far as you are concerned, this one-to-one relation management happens “automagically.”

Figure 3.6. Stateful bean session maintenance. There is a bean instance reserved for a client and each instance stores the client’s state information. The bean instance exists until either removed by the client or timed out.

The one-to-one mapping between a client and a bean instance makes saving bean conversational state in a useful manner possible. However, this one-to-one correlation comes at a price. Bean instances cannot be readily returned to the pool and reused while a client session is still active. Instead, a bean instance must be squirreled away in memory to wait for the next request from the client owning the session. As a result, stateful session bean instances held by a large number of concurrent clients can have a significant memory footprint. An optimization technique called passivation, which we’ll discuss soon, is used to alleviate this problem. Stateful session beans are ideal for multistep, workflow-oriented business processes. In this section, we explore stateful beans by using the ActionBazaar bidder account creation workflow as an example.

We describe a use case of our ActionBazaar application and implement it using a stateful session bean. We show you additional programming rules for stateful session beans, and then we examine stateful bean lifecycle callback methods and the @Remove annotation. Finally, we summarize differences between stateless and stateful session beans.

However, before we jump into code, let’s briefly examine the rules specific to developing a stateful session bean.

3.3.1. Additional programming rules

In section 3.1.3, we discussed the programming rules that apply to all session beans. Stateful session beans have a few minor twists on these rules:

  • Stateful bean instance variables used to store conversational state must be Java primitives or Serializable objects. We’ll talk more about this requirement when we cover passivation.
  • Since stateful session beans cannot be pooled and reused like stateless beans, there is a real danger of accumulating too many of them if we don’t have a way to destroy them. Therefore, we have to define a business method for removing the bean instance by the client using the @Remove annotation. We’ll talk more about this annotation soon.
  • In addition to the PostConstruct and PreDestroy lifecycle callback methods, stateful session beans have the PrePassivate and PostActivate lifecycle callback methods. A PrePassivate method is invoked before a stateful bean instance is passivated and PostActivate is invoked after a bean instance is brought back into the memory and is method ready.

You’ll see these rules applied when we explore a concrete stateful session beans example next. As we did for stateless beans, we’ll utilize the example as a jumping-off point to detail stateful features.

3.3.2. The BidderAccountCreatorBean example

The process to create an ActionBazaar bidder account is too involved to be implemented as a single-step action. As a result, account creation is implemented as a multistep process. At each step of the workflow, the would-be bidder enters digestible units of data. For example, the bidder may enter username/password information first; then biographical information such as name, address, and contact information; then billing information such as credit card and bank account data; and so forth. At the end of a workflow, the bidder account is created or the entire task is abandoned. This workflow is depicted in figure 3.7.

Figure 3.7. The ActionBazaar bidder account creation process is broken up into multiple steps: entering username/password, entering biographical information, entering billing information, and finally creating the account. This workflow could be implemented as a stateful session bean.

Each step of the workflow is implemented as a method of the BidderAccountCreatorBean presented in listing 3.2. Data gathered in each step is incrementally cached into the stateful session bean as instance variable values. Calling either the cancelAccountCreation or createAccount method ends the workflow. The createAccount method creates the bidder account in the database and is supposed to be the last “normal” step of the workflow. The cancelAccountCreation method, on the other hand, prematurely terminates the process when called by the client at any point in the workflow and nothing is saved into the database. The full version of the code is available for download in the zip containing code examples from this book’s website.

Listing 3.2. Stateful session bean example

As we mentioned earlier, it should not surprise you that the code has a lot in common with the stateless session bean code in listing 3.1.


Note

As before, we are using JDBC for simplicity in this example because we want you to focus on the session bean code right now and not JPA. We’ll cover JPA in the part 3 of this book. An interesting exercise for you is to refactor this code using JPA and notice the radical improvement over JDBC!


We are using the @Stateful annotation to mark the BidderAccountCreatorBean POJO . Other than the annotation name, this annotation behaves exactly like the @Stateless annotation, so we won’t mention it any further. The bean implements the BidderAccountCreator remote business interface. As per stateful bean programming rules, the BidderAccountCreatorBean has a no-argument constructor.

Just like in listing 3.1, a JDBC data source is injected using the @Resource annotation. Both the PostConstruct and PostPassivate 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 close the cached connection.

The loginInfo, biographicalInfo, and billingInfo instance variables are used to store client conversational state across business method calls . Each of the business methods models a step in the account creation workflow and incrementally populates the state instance variables. The workflow is terminated when the client invokes either of the @Remove annotated methods .

There is no point to repeating our discussion of the features that are identical to the ones for stateless session beans, so we’ll avoid doing so. However, let’s explore the features unique to stateful session beans next, starting with the stateful bean business interfaces.

3.3.3. Business interfaces for stateful beans

Specifying stateful bean business interfaces works in almost exactly the same way as it does for stateless beans—with a couple of exceptions. Stateful session beans support local and remote invocation through the @Local and @Remote annotations. However, a stateful session bean cannot have a web service endpoint interface. This is because SOAP-based web services are inherently stateless in nature. Also, you should always include at least one @Remove annotated method in your stateful bean’s business interface. The reason for this will become clear as we discuss the stateful bean lifecycle next.

3.3.4. Stateful bean lifecycle callbacks

As we mentioned in section 3.1, the lifecycle of the stateful session bean is very different from that of a stateless session bean because of passivation. In this section, we explain this concept in more depth. Let’s start by looking at the lifecycle of a stateful bean, as shown in figure 3.8. The container follows these steps:

1.  

Always creates new bean instances using the default constructor whenever a new client session is started.

2.  

Injects resources.

3.  

Stores the instance in memory.

4.  

Executes the requested business method invoked through the business interface by the client.

5.  

Waits for and executes subsequent client requests.

6.  

If the client remains idle for a period of time, the container passivates the bean instance. Essentially, passivation means that the bean is moved out of active memory, serialized, and stored in temporary storage.

7.  

If the client invokes a passivated bean, it is activated (brought back into memory from temporary storage).

8.  

If the client does not invoke a passivated bean instance for a period of time, it is destroyed.

9.  

If the client requests the removal of a bean instance, it is first activated if necessary and then destroyed.

Figure 3.8. The lifecycle of a stateful session bean. A stateful bean maintains client state and cannot be pooled. It may be passivated when the client is not using it and must be activated when the client needs it again.

Like a stateless session bean, the stateful session bean has lifecycle callback methods, or callbacks, that are invoked when the PostConstruct event occurs (as an instance is created) and when the PreDestroy event occurs (before the instance is destroyed). But now we have two new callback events for which we can have callbacks: PrePassivate and PostActivate, which are part of the passivation process. We’ll discuss them next.

Just as in listing 3.1, we use a PostConstruct callback in listing 3.2 to open a database connection from the injected data source so that it can be used by business methods. Also as in listing 3.1, we close the cached connection in preparation for bean destruction in a PreDestroy callback. However, you should note that we invoke the very same method for both the PreDestroy and PrePassivate callbacks:

@PrePassivate
@PreDestroy
public void cleanup() {
...
}

Similarly, the exact same action is taken for both the PostConstruct and PostActivate callbacks:

@PostConstruct
@PostActivate
public void openConnection() {
...
}

To see why this is the case, let’s discuss activation and passivation in a little more detail.

Passivation and activation

If clients don’t invoke a bean for a long enough time, it is not a good idea to continue keeping it in memory. For a large number of beans, this could easily make the machine run out of memory. The container employs the technique of passivation to save memory when possible.


Note

Passivation essentially means saving a bean instance into disk instead of holding it in memory. The container accomplishes this task by serializing the entire bean instance and moving it into permanent storage like a file or the database. Activation is the opposite of passivation and is done when the bean instance is needed again. The container activates a bean instance by retrieving it from permanent storage, deserializing it, and moving it back into memory. This means that all bean instance variables that you care about and should be saved into permanent storage must either be a Java primitive or implement the java.io. Serializable interface.


The point of the PrePassivate callback is to give the bean a chance to prepare for serialization. This may include copying nonserializable variable values into Serializable variables and clearing unneeded data out of those variables to save total disk space needed to store the bean. Most often the prepassivation step consists of releasing heavy-duty resources such as open database, messaging server, and socket connections that cannot be serialized. A well-behaved bean should ensure that heavy-duty resources are both closed and explicitly set to null before passivation takes place.

From the perspective of a bean instance, there isn’t much of a difference between being passivated and being destroyed. In both cases, the current instance in memory would cease to exist. As a result, in most cases you’ll find that the same actions are performed for both the PreDestroy and PrePassivate callbacks, as we do in listing 3.2. Pretty much the same applies for the PostConstructPostActivate pair. For both callbacks, the bean needs to do whatever is necessary to make itself ready to service the next incoming request. Nine times out of ten, this means getting hold of resources that either are not instantiated or were lost during the serialization/deserialization process. Again, listing 3.2 is a good example since the java.sql.Connection object cannot be serialized and must be reinstantiated during activation.

Destroying a stateful session bean

In listing 3.2, the cancelAccountCreation and createAccount methods are marked with the @Remove annotation. Beyond the obvious importance of these methods in implementing vital workflow logic, they play an important role in maintaining application server performance. Calling business methods marked with the @Remove annotation signifies a desire by the client to end the session. As a result, invoking these methods triggers immediate bean destruction.

To gain an appreciation for this feature, consider what would happen if it did not exist. If remove methods were not an option, the client would have no way of telling the container when a session should be ended. As a result, every stateful bean instance ever created would always have to be timed out to be passivated (if the container implementation supports passivation) and timed out again to be finally destroyed. In a highly concurrent system, this could have a drastic performance impact. The memory footprint for the server would constantly be artificially high, not to mention how there would be wasted CPU cycles and disk space used in the unnecessary activation/passivation process. This is why it is critical that you remove stateful bean instances when the client is finished with its work instead of relying on the container to destroy them when they time out.

Believe it or not, these are the only few stateful bean–specific features that we needed to talk about! Before concluding this section on stateful beans, we’ll briefly summarize the differences between stateful and stateless session beans as a handy reference in table 3.2.

Table 3.2. The main differences between stateless and stateful session beans

Features

Stateless

Stateful

Conversational state

No

Yes

Pooling

Yes

No

Performance problems

Unlikely

Possible

Lifecycle events

PostConstruct, PreDestroy

PostConstruct, PreDestroy, PrePassivate, PostActivate

Timer (discussed in chapter 5)

Yes

No

SessionSynchronization for transactions (discussed in chapter 6)

No

Yes

Web services

Yes

No

Extended PersistenceContext (discussed in chapter 9)

No

Yes

Thus far we have explored how to develop session beans. In the next section, we discuss how session beans are actually accessed and used by clients.

3.4. Session bean clients

A session bean works for a client and may either be invoked by local clients collocated in the same JVM or by a remote client outside the JVM. In this section we first discuss how a client accesses a session bean and then see how the @EJB annotation is used to inject session bean references.

Almost any Java component can be a session bean client. 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. However, in this section we concentrate on clients that access session beans either locally or remotely through RMI. In chapter 15 you’ll see how EJB web service clients look.

Fortunately, in EJB 3 accessing a remote or local session bean looks exactly the same. As a matter of fact, other than method invocation patterns, stateless and stateful session beans pretty much look alike from a client’s perspective too. In all of these cases, a session bean client follows these general steps to use a session bean:

1.  

The client obtains a reference to the beans directly or indirectly from JNDI.

2.  

All session bean invocations are made through an interface appropriate for the access type.

3.  

The client makes as many method calls as are necessary to complete the business task at hand.

4.  

In case of a stateful session bean, the last client invocation should be a remove method.

To keep things as simple as possible, let’s explore a client that uses the BidManagerBean stateless session bean to add a bid to the ActionBazaar site. We’ll leave it as an exercise for you to extend the client code to use the BidderAccountCreatorBean stateful session bean. For starters, let’s see how the code to use the BidManagerBean from another EJB might look:

@Stateless
public class GoldBidderManagerBean implements GoldBidderManager {
@EJB
private BidManager bidManager;

public void addMassBids(List<Bid> bids) {
for (Bid bid : bids) {
bidManager.addBid(bid);
}
}
}

This code uses dependency injection through the @javax.ejb.EJB annotation to obtain a reference to the BidManagerBean. This is by far the easiest method of procuring a reference to a session bean. Depending on your client environment, you might have to use one of the two other options available for obtaining EJB references: using EJB context lookup or using JNDI lookup. Since neither of these options is used often in real life, we’ll focus on DI for right now. However, we’ll discuss both EJB context lookup and JNDI lookup in greater detail in coming chapters, as well as in appendix A.

3.4.1. Using the @EJB annotation

Recall from our discussion on DI in chapter 2 that the @EJB annotation is specifically intended for injecting session beans into client code. Also recall that since injection is only possible within managed environments, this annotation only works inside another EJB, in code running inside an application-client container (ACC), or in components registered with the web container (such as a servlet or JSF backing bean). However, some application servers will support injection of EJB references into POJOs as a vendor-specific extension. Here is the specification for the @EJB annotation:

@Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
public @interface EJB {
String name() default "";
Class beanInterface() default Object.class;
String beanName() default "";
}

All three of the parameters for the @EJB annotation are optional. The name element suggests the JNDI name that is used to bind the injected EJB in the environment-naming context. The beanInterface specifies the business interface to be used to access the EJB. The beanName element allows us to distinguish among EJBs if multiple EJBs implement the same business interface. In our GoldBidManagerBean code, we chose to use the remote interface of the BidManagerBean. If we want to use the local interface of the BidManagerBean EJB instead, we can use the following:

@EJB
private BidManagerLocal bidManager;

We have not specified the name parameter for the @EJB annotation in this code and the JNDI name is derived from the interface name (BidManagerLocal in our case). If we want to inject an EJB bound to a different JNDI name, we can use the @EJB annotation as follows:

@EJB(name="BidManagerRemote")
private BidManager bidManager;

3.4.2. Injection and stateful session beans

For the most part, using DI is a no-brainer. There are a few nuances to keep an eye on while using DI with stateful beans, though. You can inject a stateful session into another stateful session bean instance if you need to. For example, you can inject the BidderAccountCreator stateful EJB from UserAccountRegistration EJB that is another stateful session bean as follows:

@Stateful
public class UserAccountRegistrationBean
implements UserAccountRegistration {
@EJB
private BidderAccountCreator bidderAccountCreator;
...
}

This code will create an instance of BidderAccountCreatorBean which will be specifically meant for the client accessing the instance of the UserAccountRegistrationBean. If the client removes the instance of UserAccountRegistrationBean, the associated instance of BidderAccountCreatorBean will also be automatically removed.

Keep in mind that you must not inject a stateful session bean into a stateless object, such as a stateless session bean or servlet that may be shared by multiple concurrent clients (you should use JNDI in such cases instead). However, injecting an instance of a stateless session bean into a stateful session bean is perfectly legal. Chapter 12 discusses in much greater detail how you can use EJB from other tiers.

This concludes our brief discussion on accessing session beans. Next, we’ll briefly explore potential performance issues of stateful session beans.

3.5. Performance considerations for stateful beans

Whether or not they deserve it, stateful session beans have received a bad rap as performance bottlenecks. There is truth behind this perception, quite possibly due to poor initial implementations for most popular application servers. In recent years, these problems have been greatly alleviated with effective under-the-hood optimizations as well as better JVM implementations. However, you still have to keep a few things in mind in order to use session beans effectively. More or less, these techniques are essential for using any stateful technology, so pay attention even if you decide against using stateful beans. In this section you’ll learn techniques to effectively use stateful session beans and other alternatives for building stateful applications.

3.5.1. Using stateful session beans effectively

There is little doubt that stateful session beans provide extremely robust business logic processing functionality if maintaining conversational state is an essential application requirement. In addition, EJB 3 adds extended persistence contexts specifically geared toward stateful session beans (discussed in chapters 9 and 13), significantly increasing their capability. Most popular application servers such as WebSphere, WebLogic, Oracle, and JBoss provide high availability by clustering EJB containers running the same stateful bean. A clustered EJB container replicates session state across container instances. If a clustered container instance crashes for any reason, the client is routed to another container instance seamlessly without losing state. Such reliability is hard to match without using stateful session beans. Nonetheless, there are a few things to watch out for while using stateful session beans.

Choosing session data appropriately

Stateful session beans can become resource hogs and cause performance problems if not used properly. Since the container stores session information in memory, if you have thousands of concurrent clients for your stateful session bean you may run out of memory or cause a lot of disk thrashing by the container as it passivates and activates instances to try to conserve memory. Consequently, you have to closely examine what kind of data you are storing in the conversation state and make sure the total memory footprint for the stateful bean is as small as possible. For example, it may be a lot more efficient to store just the itemId for an Item instead of storing the complete Item object in an instance variable.

If you cluster stateful beans, the conversational state is replicated between different instances of the EJB container. State replication uses network bandwidth. Storing a large object in the bean state may have a significant impact on the performance of your application because the containers will spend time replicating objects to other container instances to ensure high availability. We’ll discuss more about EJB clustering in chapter 13.

Passivating and removing beans

The rules for passivation are generally implementation specific. Improper use of passivation policies (when passivation configuration is an option) may cause performance problems. For example, the Oracle Application Server passivates bean instances when the idle time for a bean instance expires, when the maximum number of active bean instances allowed for a stateful session bean is reached, or when the threshold for JVM memory is reached. You have to check the documentation for your EJB container and appropriately set passivation rules. For example, if we set the maximum number of active instances allowed for a stateful bean instance to 100 and we usually have 150 active clients, the container will continue to passivate and activate bean instances, thus causing performance problems.

You can go a long way toward solving potential memory problems by explicitly removing the no longer required bean instances rather than depending on the container to time them out. As discussed earlier, you can annotate a method with the @Remove annotation that signals the container to remove the bean instance.

Given the fact that stateful session beans can become performance bottlenecks whether through improper usage or under certain circumstances, it is worth inspecting the alternatives to using them.

3.5.2. Stateful session bean alternatives

This section examines a few alternative strategies to implementing stateful business processing, as well as some issues you may need to consider when using them.

The first alternative to stateful beans is replacing them with a combination of persistence and stateless processing. In this scheme, we essentially move state information from memory to the database on every request.

You should carefully examine whether you want to maintain state between conversations in memory. Base your decision completely based on your application requirements and how much tolerance of failure you have. For example, in the BidderAccountCreator EJB you can probably avoid the use of conversational state by not maintaining instance variables to store the user information in memory and save data in the database on each method call.

Second, you may choose to build some mechanism at the client side to maintain state. This requires additional coding, such as storing the state as an object in client memory or in a file.

The downside of these two approaches is that it is difficult to guarantee high availability and they may not be viable options for your application. In fact, you would lose all of the advantages that the container provides by hand-coding proprietary solutions such as the ones outlined here, including automated passivation and robust, transparent state maintenance.

Third, you may choose to maintain session state in the web container if you’re building a web application. Although HTTP is a stateless protocol, the Java Servlet API provides the ability to maintain state by using the HttpSession object. The servlet container does not have to do heavy lifting like passivation and activation, and may perform better in certain situations. Be aware that too much data in the HttpSession could decrease performance of the servlet container as well, so this is not a silver bullet either. Moreover, you cannot use this option with thick or Java SE clients.

So when you need to maintain state in your applications and your clients are Java SE clients, then the first two options we discussed earlier may be more difficult to implement. Hence, stateful session beans are probably the only viable option as long as you carefully weigh the performance considerations we outlined earlier.

We’ll close our discussion on session beans by outlining some best practices for session beans that you can use to build your application’s business logic.

3.6. Session bean best practices

In this section we outline some of the best practices for session beans that you can use while building the business logic tier for your application.

Choose your bean type carefully. Stateless session beans will be suitable most of the time. Carefully examine whether your application needs stateful session beans, because it comes with a price. If the EJB client lies in the web tier, then using HttpSession may be a better choice than stateful session beans under some circumstances.

Carefully examine interface types for session beans. Remote interfaces involve network access and may slow down your applications. If the client will always be used within the same JVM as the bean, then use a local interface.

If you are using DI, make sure you don’t inject a stateful session bean into a stateless session bean or servlet. Injected EJB instances are stored in an instance variable and are available globally for subsequent clients even if a stateless bean instance is returned to the pool, and an injected stateful bean instance may contain inaccurate state information that will be available to a different client. It’s legal to inject a stateful bean instance to another stateful session bean or an application client.

Separate crosscutting concerns such as logging and auditing using business interceptors (which we discuss in chapter 5) instead of spreading them all over the business logic.

Closely examine what kind of data you are storing in the conversation state. Try to use small, primitive instance variables in a stateful bean whenever possible as opposed to large nested composite objects.

Don’t forget to define remove methods in a stateful session bean.

Tune passivation and timeout configurations to find the optimal values for your application.

3.7. Summary

In this chapter, we examined the various session bean types and how stateless session beans and stateful session beans differ. We looked at the programming rules for both stateless and stateful session beans, and you saw comprehensive examples of both bean types. As you learned, stateless session beans have a simple lifecycle and can be pooled. Stateful beans require instances for each client, and for that reason they can consume a lot of resources. In addition, passivation and activation of stateful beans can impact performance if used inappropriately.

You learned about alternatives for using stateful session beans, and that session bean clients can be either local or remote. We showed you that dependency injection simplifies the use of EJB and saves you from having to perform complex JNDI lookups. Finally, we provided some best practices for developing session beans.

At this point you have all the ammunition necessary to build the business logic of your application using stateless and stateful session beans. In the next chapter we’ll discuss how you can build messaging applications with messagedriven beans.