Session beans are meant to model business processes or actions, especially as perceived by the system user. This is why they are ideal for modeling the bidding and ordering processes in our scenario. Session beans are the easiest but most versatile part of EJB.
Recall that session beans come in two flavors: stateful and stateless. We’ll take on stateless session beans first, primarily because they are simpler. You’ll then discover how you can add statefulness to the ActionBazaar application by using a stateful session bean. Along the way, we introduce you to an example of a session bean client in a web tier, and then build a standalone Java client for a session bean.
Using stateless beans
Stateless session beans are used to model actions or processes that can be done in one shot, such as placing a bid on an item in our ActionBazaar scenario. The addBid bean method in listing 2.1 is called from the ActionBazaar web tier when a user decides to place a bid. The parameter to the method, the Bid object, represents the bid to be placed. The Bid object contains the ID of the bidder placing the bid, the ID of the item being bid on, and the bid amount. As we know, all the method needs to do is save the passed-in Bid data to the database. In a real application, you would see more validation and error-handling code in the addBid method. Since the point is to show you what a session bean looks like and not to demonstrate the uber geek principles of right and proper enterprise development, we’ve conveniently decided to be slackers. Also, as you’ll see toward the end of the topic, the Bid object is really a JPA entity.
Listing 2.1 PlaceBid stateless session bean code
The first thing that you have probably noticed is how plain this code looks. The PlaceBidBean class is just a plain old Java object (POJO) and the PlaceBid interface is a plain old Java interface (POJI). There is no cryptic EJB interface to implement, class to extend, or confusing naming convention to follow. In fact, the only notable features in listing 2.1 are the two EJB 3 annotations: @Stateless and @Local:
■ @Stateless—The @Stateless annotation tells the EJB container that PlaceBidBean is a stateless session bean. This means that the container automatically provides such services to the bean as automatic concurrency control, thread safety, pooling, and transaction management. In addition, you can add other services for which stateless beans are eligible, such as transparent security and interceptors.
■ @Local—The @Local annotation on the PlaceBid interface tells the container that the PlaceBid EJB can be accessed locally through the interface. Since EJB and servlets are typically collocated in the same application, this is probably perfect. Alternatively, we could have marked the interface with the @Remote annotation. Remote access through the @Remote annotation is provided under the hood by Java Remote Method Invocation (RMI), so this is the ideal means of remote access from Java clients.
If the EJB needs to be accessed by non-Java clients like Microsoft .NET applications, web services-based remote access can be enabled using the @WebService annotation applied either on the interface or the bean class.
That’s pretty much all we’re going to say about stateless session beans for now. Let’s now turn our attention to the client code for using the PlaceBid EJB.
The stateless bean client
Virtually any client can use the PlaceBid EJB in listing 2.1. However, the most likely scenario for EJB usage is from a Java-based web tier. In the ActionBazaar scenario, the PlaceBid EJB is probably called from a JavaServer Page (JSP) or serv-let. For simplicity, let’s assume that the PlaceBid EJB is used by a servlet named PlaceBidServlet. Listing 2.2 shows how the code might look. The servlet’s service method is invoked when the user wants to place a bid. The bidder’s ID, item ID, and the bid amount are passed in as HTTP request parameters. The servlet creates a new Bid object, sets it up, and passes it to the EJB addBid method.
Listing 2.2 A simple servlet client for the PlaceBid EJB
As you can see in listing 2.2, EJB from the client side looks even simpler than developing the component code. Other than the @EJB annotation on the place-Bid private variable, the code is no different than using a local POJO.
NOTE When the servlet container sees the @ejb annotation as the servlet is first loaded, it looks up the PlaceBid EJB behind the scenes and sets the placeBid variable to the retrieved EJB reference. If necessary, the container will look up the EJB remotely over RMI.
The @EjB annotation works in any component that is registered with the Java EE container, such as a servlet or JavaServer Faces (JSF) backing bean. As long as you are using the standard Java EE stack, this is probably more than sufficient.
EJB 3 dependency injection
Although we mentioned DI in the beginning of the topic, if you are not familiar with it you may think that what the @EjB annotation is doing is a little unusual—in a nifty, "black-magic" kind of way. In fact, if we didn’t tell you anything about the code, you might have been wondering if the placeBid private variable is even usable in the servlet’s service method since it is never set! If fact, if the container didn’t intervene we’d get the infamous java.lang.NullPointerException when we tried to call the addBid method in listing 2.2 since the placeBid variable would still be null. One interesting way to understand DI is to think of it as "custom" Java variable instantiation. The @EJB annotation in listing 2.2 makes the container "instantiate" the placeBid variable with the EJB named PlaceBid before the variable is available for use.
Recall our discussion in section 2.1.2 that DI can be viewed as the opposite of JNDI lookup. Recall also that JNDI is the container registry that holds references to all container-managed resources such as EJBs. Clients gain access to session beans like our PlaceBid EJB directly or indirectly through JNDI. In EJB 2, you would have to manually populate the placeBid variable using JNDI lookup code that looks like the following:
It isn’t easy to fully appreciate DI until you see code like this. EJB 3 DI using the @ejb annotation reduces all this mechanical JNDI lookup code to a single statement! In a nontrivial application, this can easily translate to eliminating hundreds of lines of redundant, boring, error-prone code. You can think of EJB 3 DI as a high-level abstraction over JNDI lookups.
An interesting point about the PlaceBid stateless bean is that as long as calling the addBid method results in the creation of a new bid record each time, the client doesn’t care about the internal state of the bean. There is absolutely no need for the stateless bean to guarantee that the value of any of its instance variables will be the same across any two invocations. This property is what statelessness means in terms of server-side programming.
The PlaceBid session bean can afford to be stateless because the action of placing a bid is simple enough to be accomplished in a single step. The problem is that not all business processes are that simple. Breaking a process down into multiple steps and maintaining internal state to "glue together" the steps is a common technique to present complex processes to the user in a simple way. Statefulness is particularly useful if what the user does in a given step in a process determines what the next step is. Think of a questionnaire-based setup wizard. The user’s input for each step of the wizard is stored behind the scenes and is used to determine what to ask the user next. Stateful session beans make maintaining server-side application state as easy as possible.
Using stateful beans
Unlike stateless session beans, stateful session beans guarantee that a client can expect to set the internal state of a bean and count on the state being maintained between any number of method calls. The container makes sure this happens by doing two important things behind the scenes.
Maintaining the session
First, the container ensures that a client can reach a bean dedicated to it across more than one method invocation. Think of this as a phone switchboard that makes sure it routes you to the same customer service agent if you call a technical support line more than once in a given period of time (the period of time is the "session").
Second, the container ensures that bean instance variable values are maintained for the duration of a session without your having to write any session maintenance code. In the customer service example, the container makes sure that your account information and call history in a given period of time automatically appear on your agent’s screen when you call technical support. This "automagic" maintenance of session state is a huge leap from having to fiddle with the HTTP session, browser cookies, or hidden HTML form variables to try to accomplish the same thing. As we’ll see in the coming code samples, you can develop stateful beans as if you are developing in a "Hello World" application, not a web application with verbose code to maintain session state. The ActionBazaar ordering process is a great example for stateful session beans since it is broken up into four steps, each of which correspond to a screen presented to the user:
1 Adding items to the order. If the user started the ordering process by clicking the Order Item button on the page displaying an item won, the item is automatically added to the order. The user can still add additional items in this step.
2 Specifying shipping information, including the shipping method, shipping address, insurance, and so on.
3 Adding billing information, such as credit card data and the billing address.
4 Confirming the order after reviewing the complete order, including total cost.
Figure 2.4 To make an otherwise overwhelming process manageable, the ActionBazaar ordering process is broken down into several steps. The first of these steps is to add one or more item to the order. The second step is to specify shipping information for the order. The third is to specify the billing information. Reviewing and confirming the order finishes the ordering process.
Figure 2.4 depicts these ordering steps. With a stateful bean, the data the user enters at each step can be cached into bean variables until the ordering workflow completes, when the user confirms the order.
Now that we know what we want, let’s see how we can implement it.
Implementing the solution
Listing 2.3 shows a possible implementation of the ActionBazaar ordering workflow using a bean named PlaceOrderBean. As you can see, each of the ordering steps maps to a method in the PlaceOrderBean implementation. The addItem, set-ShippingInfo, setBillingInfo, and confirmOrder methods are called in sequence from the web tier in response to user actions in each step. The setBidderID method essentially represents an implicit workflow setup step. It is called at the beginning of the workflow behind the scenes by the web application to identify the currently logged-in user as the bidder placing the order. Except for the confirm-Order method, the remaining methods do little more than simply save user input into stateful instance variables. In a real application, of course, these methods would be doing a lot more, such as error handling, validation, figuring out the user’s options for a given step, calculating costs, and so on. The confirmOrder method does several things using the data accumulated throughout the session: the complete order is saved into the database, the billing process is started in parallel, and an order ID is returned to the user as confirmation.
Listing 2.3 PlaceOrderBean stateful session bean
As you can see, overall there is no big difference between developing a stateless and a stateful bean. In fact, from a developer’s perspective, the only difference is that the PlaceOrderBean class is marked with the @Stateful annotation instead of the @Stateless annotation Q. As we know, though, under the hood this makes a huge difference in how the container handles the bean’s relationship to a client and the values stored in the bean instance variables Q. The @Stateful annotation also serves to tell the client-side developer what to expect from the bean if behavior is not obvious from the bean’s API and documentation.
It is also important to note the @Remove annotation G placed on the confirm-Order method. Although this annotation is optional, it is critical from a server performance standpoint.
NOTE The @Remove annotation marks the end of the workflow modeled by a stateful bean. In our case, we are telling the container that there is no longer a need to maintain the bean’s session with the client after the confirmOrder method is invoked. If we didn’t tell the container what method invocation marks the end of the workflow, the container could wait for a long time until it could safely time-out the session. Since state-ful beans are guaranteed to be dedicated to a client for the duration of a session, this could mean a lot of "orphaned" state data consuming precious server resources for long periods of time!
Let’s now take a quick look at stateful beans from the client perspective. As you might expect, compared to stateless beans there are no major semantic differences.
A stateful bean client
It is clear that the PlaceOrder EJB is called from the ActionBazaar web tier. However, to give a slightly more colorful perspective on things, we’ll deliberately stay out of web-tier client examples this time. We’ll use a thick Java application that functions as a test script to run through the entire workflow of the PlaceOrder EJB using some dummy data. This test script could have just as easily been part of a very high-level regression test suite using a framework like JUnit or NUnit.
NOTE If you have management buy-in to invest in extensive unit testing, you might also note the fact that because of the POJO-centric nature of EJB 3, our example application could be easily modified to a full-scale unit test using dummy data sources and the like.If unit testing and code coverage are not viable topics to bring up in your work environment, don’t worry; we don’t assume you do a ton of unit testing.
Listing 2.4 shows the code for the stateful session bean client.
Listing 2.4 Stateful session bean client
There is nothing special you need to do from the client side to use stateful beans. As a matter of fact, there is virtually no difference in the client code between using a stateless and a stateful bean, other than the fact that the client can safely assume that the EJB is maintaining state even if it is sitting on a remote application server. The other remarkable thing to note about listing 2.4 is the fact that the @ejb annotation is injecting a remote EJB into a standalone client. This is accomplished by running the client in the application client container (ACC).
NOTE The application client container is a mini Java EE container that can be run from the command line. Think of it as a souped-up Java Virtual Machine (JVM) with some Java EE juice added. You can run any Java SE client such as a Swing application inside the ACC as if you were using a regular old JVM. The beauty of it is that the ACC will recognize and process most Java EE annotations such as the @EJB DI annotation. Among other things, the client container can look up and inject EJBs on remote servers, communicate with remote EJBs using RMI, provide authentication, perform authorization, and so forth. The application client really shines if you need to use EJBs in an SE application or would like to inject real resources into your POJO during unit testing.
Any Java class with a main method can be run inside the ACC. Typically, though, an application client is packaged in a JAR file that must contain a MainClass in the Manifest file. Optionally, the JAR may contain a deployment descriptor (application-client.xml) and a jndi.properties file that contains the environment properties for connecting to a remote EJB container. Let’s assume you packaged up your application client classes in a JAR file named topic 2-client. jar. Using Sun Microsystems’s GlassFish application server, you could launch your application client inside the ACC as follows: