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 beween stateless and stateful session beans.
Why use session beans?
Session beans are a lot more than just business logic holders. Remember the EJB services we briefly mentioned in topic 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 topic 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 topic.
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 topic, but topic 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 topic 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 topic 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.
Session beans: the basics
Although we briefly touched on session beans in the previous topic, we didn’t go into great detail about developing them. Before we dive in, let’s revisit the code in topic 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 topic 2, the bean implementation consisted of the PlaceBid interface and the PlaceBidBean class, as shown in figure 3.1.
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.
Figure 3.1 Parts of the PlaceBid session bean. Each session bean has one or more interfaces and one implementation class.
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 topic 2:
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 topic 2:
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.
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.
■ 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.
■ 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 @state-ful 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.
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 state-ful session bean.
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.
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.
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.
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.
Table 3.1 lists the lifecycle callback method annotations, where they are applied, and what the callback methods are typically used for.
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 topic 5.
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.
At this point, let’s launch our detailed exploration with the simpler stateless session bean model and save stateful session beans for later.