- What Does a Session Bean Do?
- A "Hello World" Session Bean
- More Details About Session Beans
- Creating a Stateless Session Bean
- Troubleshooting
More Details About Session Beans
Now that you have a feel for the structure of session beans and what it takes to implement them, there are a few more details you need to know to be more effective when designing and developing session beans.
The SessionBean Interface
Every session bean must implement the SessionBean interface, which contains four methods. The EJB container uses these methods to manage the session bean.
setSessionContext
A SessionContext object contains information about the environment the session bean is running in. It contains a reference to the bean's Home interface, a reference to the bean itself, transaction information, and the identity of the caller who invoked a specific method.
The setSessionContext method is called once for each session bean and is part of the initialization of the bean. The bean is an active part of the EJB container after setSessionContext and remains active until the ejbRemove method is called.
Tip
The setSessionContext method is a great place to put initialization code. You might, for instance, want to create a database connection or locate another bean's Home interface in setSessionContext.
Of the methods in the SessionContext interface, getEJBObject is the one that you'll probably call the most. Sometimes, an EJB must pass itself to another method call. For example, suppose you have a ShoppingCart session bean that contains items that a user wants to order. Furthermore, suppose that you have an OrderPlacement session bean that takes the contents of a shopping cart and enters it into your ordering system. You often find situations like this when a company has an existing ordering system, possibly even on a mainframe. If you ever plan to migrate the ordering system to another platform, maybe from the mainframe to an EJB server, you want to design the ShoppingCart bean so it doesn't care how the order is entered-its only task is to manage the items you want to buy. The OrderPlacement bean takes care of placing the order. When you change over to a new ordering system, just change the OrderPlacement bean and leave the shopping cart alone.
Now, when the ShoppingCart bean needs to call the OrderPlacement bean, you would think it could just pass itself using the this keyword. In other words, it might do something like this:
orderPlacementBean.submitOrder(this);
The problem here is that the submitOrder method is probably declared something like this:
public void submitOrder(ShoppingCart cart) throws RemoteException;
This is a problem because ShoppingCart is a Remote interface for a session bean (for this example, at least). The this variable would refer to a ShoppingCartImpl object, however, which doesn't implement the ShoppingCart interface. When you first start working with EJBs, these distinctions can be a little confusing. An EJB really has two parts: the Remote interface and the implementation. The implementation is not a remote object. That is, it does not implement the Remote interface. In fact, in many EJB implementations, the Remote interface invokes a method in the container, and the container invokes a method in the implementation, just as it does for the standard methods, such as ejbCreate and ejbRemove.
The correct way to call the submitOrder would be
orderPlacementBean.submitOrder((ShoppingCart) sessionContext.getEJBObject());
This code assumes, of course, that your setSessionContext method does this:
public void setSessionContext(SessionContext aContext) { sessionContext = aContext; }
Even if you don't need the session context in your bean, it's still a good idea to keep track of it. It only takes a few lines of code and you can always count on it being there.
Tip
If you decide to make it a standard practice to keep the session context, make sure you also standardize the access to the context. In other words, either pick a standard variable name for the context that every developer can count on, or create a standard method name, such as getSessionContext.
ejbRemove
The EJB container calls a session bean's ejbRemove method to tell the bean it is going out of service. The bean should clean up any resources it is holding on to.
Tip
If your bean establishes a database connection in the setSessionContext method, close down the connection in the ejbRemove method. If you create any session beans, remove them in the ejbRemove method, and if you locate any Home interfaces, set them to null.
ejbPassivate and ejbActivate
One of the interesting aspects of the Enterprise JavaBeans specification is that it pro- vides various ways for EJB containers to do load balancing and various other kinds of performance-related operations. Passivation/activation is one such operation, and it is similar to the way your computer manages memory.
Most modern operating systems use a concept called virtual memory, where instead of keeping everything in RAM memory, the operating system writes some information out to disk.
Over time, the least-recently used memory areas are written to disk (this technique is called "swapping"). You might notice sometimes that if you start up an application and then minimize or iconify it (depending on what windowing environment you are using) and run a lot of things, it takes a while to display the application when you finally try to access it again. This happens because application's memory areas were written out to disk to free up space for the other stuff you were running. The delay is caused by the computer reading the information back off the disk.
The ejbPassivate and ejbActivate methods allow an EJB container to perform swapping. If, at some point, the EJB container realizes that it has a lot of beans in memory that haven't been accessed in a while, it might choose to store some of those beans to disk. The idea is that the EJB container uses object serialization to store infrequently used beans to a file somewhere. This process, in EJB, is called passivation. When a client tries to access a passivated bean, the EJB container activates the bean again by reading it back from the disk.
The ejbPassivate and ejbActivate methods help the EJB container solve a messy problem-you can't serialize certain "live" operating system resources such as network connections. Because most database connections involve a network connection, this means you can't serialize database connections, either.
If you establish a database connection in your setSessionContext method, you must do something with that connection when the EJB container needs to passivate the session bean. Specifically, you should close the connection and set the connection variable to null. When the EJB container calls your ejbActivate method, re-establish the connection.
Tip
Don't be fooled into thinking that ejbActivate is called when the session bean is first created. The ejbActivate method is only called sometime after the ejbPassivate method has been called.
Session Bean Requirements, Restrictions, and Permissions
The EJB specification places some specific restrictions and requirements on session beans. Some of these requirements indicate things that a bean must do, others indicate things a bean must not do, and others specify methods and interfaces that a bean must implement. There are also things that the specification specifically allows, just in case you might get the impression that they were forbidden by other restrictions.
Implement the SessionBean Interface
You probably wouldn't think of creating a session bean that doesn't implement javax.ejb.SessionBean, but just in case the thought crosses your mind, forget it!
Declare the Class as Public, and Not Final or Abstract
Remember that the EJB container needs to create instances of the bean, so the class must be public and concrete (non-abstract).
Create a Public, Parameterless Constructor
Again, the EJB container must create instances of the bean. If the constructor is protected or private, the container can't create the instance.
Don't Implement a finalize Method
Although you rarely need to define a finalize method in the first place, the EJB specification explicitly forbids finalize in both session and entity beans. If your bean needs to do any cleanup, it should do it in the ejbRemove method or in ejbPassivate.
Implement the create Method and Any remote Methods
A session bean must implement any create methods specified in the Home interface, and all methods specified in the Remote interface. In implementing these methods, there are several additional requirements:
-
The methods must be public and cannot be static or final.
-
The parameters and return types must be valid RMI/IIOP return types. In general, this means that they must either be native types (int, char, double, and so on), serializable objects, or Remote interfaces.
-
The method name can't start with ejb (this might confuse an EJB deploy tool and possibly create conflicts).
Optionally Implement the Remote Interface
It might sound strange to say that a bean can implement the Remote interface, but is not required to. The distinction is subtle but extremely important. The methods in the implementation class must have the same method signatures as those in the Remote interface, except that the methods in the implementation class are not required to throw RemoteException. In other words, although every method in the Remote interface must have a corresponding method in the implementation class, the implementation isn't required to implement the Remote interface with a declaration like this:
public class ShoppingCartImpl implements SessionBean, ShoppingCart
The reason you might be tempted to implement the Remote interface is that the compiler will then tell you when you miss a method. In other words, if your implementation class doesn't implement a method in the Remote interface, the compiler generates an error. Otherwise, you won't know about the missing method until you run a deployment tool or a packaging tool. The longer it takes you to learn about an error, the longer it takes to fix it because you must repeat more steps.
The problem with implementing the Remote interface is that you might accidentally try to pass the object using the this keyword when you should really be using the getEJBObject method in the session context. Normally, when you accidentally use this instead of getEJBObject, the compiler generates an error because it is expecting an object that implements the Remote interface, and the implementation class doesn't. By implementing the Remote interface, you get around the compiler error, but you end up with a runtime error because the implementation is not really a proper reference to a Remote interface as the EJB container expects.
Tip
Although implementing the Remote interface can point out errors at compile time, it can also cause errors that might not be discovered until runtime, which can be much costlier to fix. You are better off not implementing the Remote interface and discovering some errors at deployment time.
Optionally Implement the SessionSynchronization Interface
The SessionSynchronization interface gives a session bean better control over how a transaction takes place. You will learn more about this interface and how to use it in Chapter 8, "Using Container-Managed Persistence."
Subclass Another Class When Necessary
Just in case you were worried about it, your implementation class might be a subclass of another class. In fact, that superclass could even be the implementation class for another kind of bean.
Implement Helper Methods as Necessary
An implementation class might have additional helper methods that are not part of the Remote or Home interfaces. There are no restrictions on the kinds of parameters, the return type, or the visibility (public, protected, private) of the method.
Don't Throw RemoteException
If you need to throw an EJB-related exception, throw javax.ejb.EJBException instead.
Remote and Home Interface Restrictions
In addition to the restrictions on the implementation class, there are some restrictions on the Remote and Home interfaces. Most of these restrictions are similar to ones you have already seen for the implementation class.
Remote Interfaces Must Extend javax.ejb.EJBObject
When you use some deployment tools, such as the one provided by WebLogic, you'll notice that it automatically knows which class contains the Remote interface. It looks for the EJBObject interface to detect a Remote interface. Furthermore, the EJBObject interface contains some additional methods that every EJB must implement.
Home Interfaces Must Extend javax.ejb.EJBHome
As with the Remote interfaces an EJBObject, the EJBHome interface helps identify Home interfaces and defines some methods that you can invoke on every Home interface.
Parameters and Return Types Must Be Valid for RMI/IIOP
Again, this generally means the types must either be native types, serializable objects, or Remote interfaces.
All Methods Must Throw java.rmi.RemoteException
Because the Home and Remote interfaces extend the java.rmi.Remote interfaces, all the methods in the interfaces must throw java.rmi.RemoteException. The RMI specification explicitly requires all methods in a remote interface to throw RemoteException.
All Methods Must Have Corresponding Implementations
Normally, in a typical RMI implementation, this would go without saying because the implementation class would implement the Remote interface. In the case of EJB, however, because the implementation class isn't required to implement the Home and Remote interfaces, the compiler can't enforce the relationship between the implementation class and the Home and Remote interfaces.
Each create method in the Home interface must have a corresponding ejbCreate method in the implementation class. Also, the create method must throw CreateException.
Interfaces Can Extend Other Interfaces
To support subclassing of Enterprise JavaBeans, the Home and Remote interfaces can extend other interfaces, as long as the parent interfaces are descendants of EJBObject (for Remote interfaces) or EJBHome (for Home interfaces).