A session bean usually exists for the lifetime of a single client session. The methods of a session bean perform a set of tasks or processes for the client that uses the bean. Session beans persist only for the life of the connection with the client. In a sense, the session bean represents the client in the EJB server. It usually provides a service to the client. Unless you need to work with persistent data that exists in a data store, you are usually working with session beans.
sortList()
business method. The client would invoke sortList()
, passing it an unsorted list of items. sortList()
would then pass back to the client a sorted list.
javax.ejb.SessionBean
interface.
ejbCreate()
methods. If you've already created the home interface for the bean, the bean must have an ejbCreate()
method with the same signature for each create()
method in the home interface.
JBuilder's Enterprise JavaBean wizard can start these tasks for you, including creating the home and remote interfaces. It creates a class that extends the SessionBean
interface and writes empty implementations of the SessionBean
methods. You fill in the implementations if your bean requires them. The next section explains what these methods are and how they are used.
SessionBean
interface defines the methods all session beans must implement. It extends the EnterpriseBean
interface.
package javax.ejb; public interface Session extends EnterpriseBean { void setSessionContext(SessionContext sessionContext) throws EJBException, RemoteException; void ejbRemove() throws EJBException, RemoteException; void ejbActivate() throws EJBException, RemoteException; void ejbPassivate() throws EJBException, RemoteException; }The methods of the
SessionBean
interface are closely associated with the life cycle of a session bean. This table explains their purpose:
Method | Description |
setSessionContext() | Sets a session context. The bean's container calls this method to associate a session bean instance with its context. The session context interface provides methods to access the runtime properties of the context in which a session runs. Usually a session bean retains its context in a data field. |
ejbRemove() | Notifies a session object that it is about to be removed. The container calls this method whenever it removes a stateful session bean as a result of the client calling a remove() method of the remote or home interface. |
ejbActivate() | Notifies a stateful session object that is has been activated. |
ejbPassivate() | Notifies a stateful session object that it is about to be deactivated by the container. |
The ejbActivate()
and ejbPassivate()
methods allow a stateful session bean to manage resources. For more information, see Stateful session beans.
ejbCreate()
methodsejbCreate()
method to the bean class that takes no parameters. You can add additional ejbCreate()
methods that do include parameters. While stateless session beans never need more than a parameterless ejbCreate()
method because they don't retain any state, stateful session beans often need one or more ejbCreate()
methods that have parameters. As you write additional ejbCreate()
methods with parameters, keep these rules in mind:
ejbCreate()
must be declared as public.
ejbCreate()
method must be of the same number and type as those in the corresponding create()
method in the bean's remote interface.
This is the signature for all ejbCreate()
methods of a session bean:
public void ejbCreate( <zero or more parameters> ) { // implementation }The
ejbCreate()
method need not throw an exception, although it can throw application-specific exceptions and other exceptions, such javax.ejb.CreateException
. The Enterprise JavaBean wizard generates an ejbCreate()
method that throws javax.ejb.CreateException
.
Not only does the Enterprise JavaBean wizard create your enterprise bean class, it also creates the bean's home and remote interfaces as it creates the bean class. This way, you are assured the create()
method of the home interface returns the remote interface while the ejbCreate(
) method always returns void.
After you write the business methods in your bean class, you can use the Bean designer to specify which of those you want defined in the bean's remote interface. A client application can access only those methods defined in the remote interface. Once you specify which methods you want a client to be able to call, the Bean designer defines the methods in the remote interface for you.
If you already have a complete enterprise bean class, but don't have home and remote interfaces for it, you can use JBuilder's EJB Interfaces wizard to create them. The method signatures will comply with EJB 1.1 specifications in the home and remote interfaces without you having to worry about making them correct.
For information about using JBuilder's EJB tools to create session beans, see the "Developing enterprise beans with JBuilder" chapter.
create()
method of the session bean's home interface. The container creates a new instance of the session bean and returns an object reference to the client.
During the creation process, the container invokes the setSessionContext()
method of the SessionBean
interface and calls the ejbCreate()
method of the session bean implementation. The new bean object joins a pool of stateless bean objects that are ready for use by clients. Because stateless session objects don't maintain client-specific state, the container can assign any bean object to handle an incoming method call. When the container removes an object from the session bean object pool, it calls the ejbRemove()
method of the bean object.
Note that calling the create()
or remove()
methods of the home/remote interfaces doesn't add or remove a stateless session bean object to or from the stateless session bean pool. The container controls the life cycle of stateless beans.
create()
method of the session bean's home interface. The container creates a new instance of the session bean, initializes it, and returns an object reference to the client.
During the creation process, the container invokes the setSessionContext()
method of the SessionBean
interface and calls the ejbCreate()
method of the session bean implementation. As a bean provider, you can use these methods to initialize the session bean.
The state of the session bean is now method ready, which means it can perform nontransaction operations or be included in a transaction for transaction operations. The bean remains in the method-ready state until one of three things happens:
When a client calls the remove()
method of the remote or home interface, the container invokes the corresponding ejbRemove()
method on the session bean object. As a bean provider, you put any application-specific cleanup code in this method. After ejbRemove()
completes, the bean object is no longer usable. If the client attempts to call a method in the bean object, the container throws the java.rmi.NoSuchObjectException
.
The container can deactivate the session bean instance. Usually this occurs for resource management reasons such as when a session object is idle for a while or if the container requires more memory. The container deactivates the bean by calling the bean's ejbPassivate()
method. When a bean instance is deactivated, which is called passivation, the container stores reference information and the state of the session object on disk and frees the memory allocated to the bean. You can add code to ejbPassivate()
if you have some task you want to execute just before passivation occurs.
The container activates the bean object again by calling the ejbActivate()
method. This occurs when the client calls a method on the session bean that is passivated. During activation, the container recreates the session object in memory and restores its state. If you want something to happen immediately after the bean becomes active again, add your code to the ejbActivate()
method.
SessionSynchronization
interface if it wants to be notified about the state of any transaction in which it is involved. Only stateful session beans using container-managed transactions can implement SessionSynchronization
; its use is optional. The methods of SessionSynchronization
are callbacks made by the container into the bean, and they mark points within the transaction. Here is the SessionSynchronization
interface:
public interface javax.ejb.SessionSynchronization { public abstract void afterBegin() throws RemoteException; public abstract void beforeCompletion() throws RemoteException; public abstract void afterCompletion(boolean completionStatus) throws RemoteException; }The Enterprise JavaBean wizard can add these methods to your bean class. Using the wizard, check the Session Synchronization check box, and the wizard declares the three methods with empty bodies in your bean class:
The following table briefly describes each method:
Method | Description |
afterBegin() | Notifies the bean instance that it is about to be used in a transaction. Any code you write within afterBegin() occurs within the scope of the transaction. |
beforeCompletion() | Notifies the bean instance that the transaction is about to commit. If the bean has any cached values, use beforeCompletion() to write them to the database. If necessary, a session bean could use the beforeCompletion() method to force the transaction to roll back by calling the setRollbackOnly() method of the SessionContext interface. |
afterCompletion() | Notifies the bean instance that the transaction has completed. If the transaction was committed, the parameter completionStatus is set to true. If the transaction was rolled back, the parameter is set to false. |
This is how the SessionSynchronization
methods are used: The client calls a transactional business method defined in the remote interface, which puts the bean object in the transaction-ready state. The container calls the afterBegin()
method in the bean object. Later, if the transaction is committed, the container calls beforeCompletion()
, and then, if the commit was successful, the afterCompletion(true)
method. If the transaction was rolled back or otherwise failed to commit, the container calls afterCompletion(false)
. The session bean object is now in method-ready state again.
For more information about using session beans in transactions, see the "Managing transactions" chapter.
CartBean
, that becomes a virtual shopping cart for an online store. Shoppers select items and put them in their virtual shopping carts. They can leave the site briefly, return, and add more things to their carts. Whenever they want, shoppers can view the items in their cart. When they are ready, they buy the items in the cart.
You can find complete code for the cart example in the /Inprise/AppServer/examples/ejb/cart directory.
These are the key files:
CartHome.java
, the file that defines the home interface for the CartBean
session bean.
Cart.java
, the file that defines the remote interface for the CartBean
session bean.
CartBean.java
, the session bean class.
Item.java
, an item file used by CartBean
. It provides methods for getting the price and title of the items that are placed in the virtual cart.
Cart.xml
, the deployment descriptor file. For EJB 1.1, an XML file contains the deployment descriptor of an enterprise bean.
CartBean
. There are three exceptions and each is defined in its own file:
ItemNotFoundException
PurchaseProblemException
CardExpiredException
CartClient.java
, the client application.
CartBean
session bean. You would begin by using the Enterprise JavaBean wizard. On the second page of the wizard, type in the name of the class as CartBean
and select the Stateful Session Bean option and click Next. Accept the suggested home interface name, the remote interface name, and the bean home name, and choose Finish. The wizard creates a skeleton bean class for you:
package shoppingcart; import java.rmi.*; import javax.ejb.*; public class CartBean implements SessionBean { private SessionContext sessionContext; public void ejbCreate() throws CreateException { } public void ejbRemove() throws RemoteException { } public void ejbActivate() throws RemoteException { } public void ejbPassivate() throws RemoteException { } public void setSessionContext(SessionContext context) throws RemoteException { sessionContext = context; } }A session bean class must be defined as public. It cannot be defined as final or abstract. The bean class must implement the
SessionBean
interface.
Session beans are Java objects, so they can have instance variables. CartBean
has four instance variables you add to the class. The four variables are declared as private:
private Vector _items = new Vector(); private String _cardHolderName; private String _creditCardNumber; private Date _expirationDate;Place these declarations after the
sessionContext
variable the Enterprise JavaBean wizard added to the class.
The _items
variable holds the items owned by the cart object. It is a vector, a collection of items. The remaining three instance variables store the credit card information of the online shopper.
SessionBean
interface. The EJB container invokes these methods on the bean instance at specific points in a session bean's life cycle. At a minimum, the bean provider must implement these methods with empty bodies. The bean provider can add additional code to these methods if it is needed. This CartBean
session bean adds no code to these methods. These are the four methods:
public void ejbRemove() {} public void ejbActivate() {} public void ejbPassivate() {} public void setSessionContext(SessionContext context) {}The Enterprise JavaBean wizard adds all four of these methods. In the
setSessionContext()
method, the wizard assigns the value of the context parameter to the sessionContext
instance variable.
The container calls the setSessionContext()
method to associate the bean instance with its session context. The bean can choose to retain this session context reference as part of its conversational state, but it's not required to do so. If you used the Enterprise JavaBean wizard, the session context reference is held. The session bean can use the session context to get information about itself, such as environment variables or its home interface.
The container calls the ejbPassivate()
method on the bean instance when it needs to place the bean instance into a passive state. The container writes the bean's current state to secondary storage when it passivates the bean. It restores this state when it later activates the bean. Because the container calls the ejbPassivate()
method just before it actual passivates the bean instance, you, as the bean provider, can add code to this method to do any special variable caching you want. Similarly, the container calls the ejbActivate()
method on the bean instance just prior to returning the bean instance to an active state from a passive state. When it activates the bean, it restores all persisted state values. You can choose to add code to the ejbActivate()
method. The CartBean
leaves these implementations empty.
While a session bean isn't required to implement a constructor, it must implement at least one ejbCreate()
method. This method serves as a constructor to create a new bean instance. A stateful session can implement more than one ejbCreate()
method. Each ejbCreate()
method would differ only in their parameters.
The CartBean
example declares one ejbCreate()
method that takes three parameters:
public void ejbCreate(String cardHolderName, String creditCardNumber, Date expirationDate) throws CreateException { _cardHolderName = cardHolderName; _creditCardNumber = creditCardNumber; }The container calls the
ejbRemove()
method just prior to removing the bean instance. You can add some application-specific code that would execute before the bean is removed, but it isn't required. The CartBean
example leaves the body of the ejbRemove()
method empty.
javax.ejb.EJBException
exception, and it may define arbitrary application-specific exceptions.
CartBean
example, five business methods are implemented. The signatures (method name, number of parameters, parameter types, and return type) of the session bean class methods must match those of the remote interface. To ensure that happens, you can use the Bean designer to move the business methods you add to the bean class to the bean's remote interface.
To help you follow the flow of the program, each business method includes a line of code that displays the method name and what it is doing.
The addItem()
method adds an item to the vector that holds the list of items in the cart:
public void addItem(Item item) { System.out.println("\taddItem(" + item.getTitle() + "): " + this); _items.addElement(item); }The
removeItem()
method is more complicated. The method loops through the elements in the item list and checks if the class and the title of the item to be removed match the class and title of one in the list. This method verifies that you are removing the item you really want removed. If no matching item is found, the method throws an ItemNotFoundException
.
public void removeItem(Item item) throws ItemNotFoundException { System.out.println("\tremoveItem(" + item.getTitle() + "): " + this); Enumeration elements = _items.elements(); while(elements.hasMoreElements()) { Item current = (Item) elements.nextElement(); // items are equal if they have the same class and title if(item.getClass().equals(current.getClass()) && item.getTitle().equals(current.getTitle())) { _items.removeElement(current); return; } }The
getTotalPrice()
method initializes the total price to zero, then loops through the item list, adding the price of each element to the total price. It returns the total price rounded to the nearest penny.
public float getTotalPrice() { System.out.println("\tgetTotalPrice(): " + this); float totalPrice = 0f; Enumeration elements = _items.elements(); while(elements.hasMoreElements()) { Item current = (Item) elements.nextElement(); totalPrice += current.getPrice(); } // round to the nearest lower penny return (long) (totalPrice * 100) / 100f; }All data types passed between a client and a server must be serializable. That is, they must implement the
java.io.Serializable
interface. In the CartBean
example, the bean returns a list of items to the client. If there were no serializable restriction, you could use _items.elements()
to return the contents of the item vector. But _items.elements()
returns a Java Enumeration
object, which is not serializable. To avoid this problem, the program implements a class called com.inprise.ejb.util.VectorEnumeration(_items)
. This class takes a vector and returns an actual enumeration, which is serializable, for the contents of that vector. The CartBean
object passes this serializable vector to the client, and receives a serializable vector passed from the client side. The getContents()
method does the conversion between a Java Enumeration
and a serializable VectorEnumeration
.
public java.util.Enumeration getContents() { System.out.println("\tgetContents(): " + this); return new com.inprise.ejb.util.VectorEnumeration(_items); }The
purchase()
method should do the following:
CardExpiredException
application exception.
CartBean
example.) If an error occurs at any point, the purchase process does not complete and the method throws a PurchaseProblemException
exception.
public void purchase() throws PurchaseProblemException { System.out.println("\tpurchase(): " + this); // make sure the credit card has not expired Date today = Calendar.getInstance().getTime(); if(_expirationDate.before(today)) { throw new CardExpiredException("Expiration date: " + _expirationDate); } // complete purchasing process // throw PurchaseProblemException if an error occurs }
CartBean
includes a toString()
method to print out the CartBean
and the name of the card holder.
// method to print out CartBean and the name of card holder public String toString() { return "CartBean[name=" + _cardHolderName + "]"; }
CartBean
example uses an Item
class. Item
is public and it extends java.io.Serializable
; serialized data can be passed on the wire:
package shoppingcart; public class Item implements java.io.Serializable { private String _title; private float _price; public Item(String title, float price) { _title = title; _price = price; } public String getTitle() { return _title; } public float getPrice() { return _price; } }
CartBean
example. All are extensions of the Java class Exception
:
public class ItemNotFoundException extends Exception { public ItemNotFoundException(String message) { super(message); } } public class PurchaseProblemException extends Exception { public PurchaseProblemException(String message) { super(message); } } public class CardExpiredException extends Exception { public CardExpiredException(String message) { super(message); } }
CartBean
session bean has a public EJB remote interface called Cart
, and a home interface called CartHome
.
When you use the Enterprise JavaBean wizard, the home and remote interfaces are created at the same time the bean class is. If you already have a session bean, but not the interfaces, use the EJB Interfaces wizard. To use the wizard, display the source code of the your enterprise bean in the code editor and choose Wizards|EJB Interfaces. Respond to the wizard's prompts and when you are done, the wizard creates a home and a remote interface for your enterprise bean.
For more information about using the Enterprise JavaBean wizard and the EJB Interfaces wizard, see the "Developing enterprise beans with JBuilder" chapter
CartHome
extends the EJBHome
interface. While the home interface can potentially perform two actions, creating bean instances and finding bean instances, session beans need only to create a bean instance. Session beans always cease to exist when a client's session ends. Therefore, there would be no need to find a CartBean
instance when a shopper enters an online store, for example, because a CartBean
instance doesn't exist. Only home interfaces for entity beans include find operations, because entity beans are used by multiple clients and persist as long as the data entities exists.
Here is the CartHome
interface:
// CartHome.java public interface CartHome extends javax.ejb.EJBHome { Cart create(String cardHolderName, String creditCardNumber, java.util.Date expirationDate) throws java.rmi.RemoteException,javax.ejb.CreateException; }The
CartHome
interface is very simple, defining a solitary create()
method. Because this is a stateful session bean, there can be more than one create()
method. In this example, create()
method in the CartHome
interface takes three parameters: cardHolderName
, creditCardNumber
, and expirationDate
.
The client invokes the create()
method to request a shopping cart and the container creates one specifically for that user. The client can use the shopping cart intermittently, but the session bean remains active for that one client until the user exits and the session bean instance is removed.
A stateful session bean maintains state across method calls, regardless of whether those methods are within the context of a transaction. The state is the data carried by an bean object. The data remains associated with the bean object for the lifetime of the object. When the session is over, the container flushes the state of session bean from memory.
The create()
method follows the rules defined in the EJB specification: it throws an RMI remote exception, java.rmi.RemoteException
, and it throws an EJB create exception, javax.ejb.CreateException
. The signature of the create()
method matches that of the ejbCreate()
method in the session bean class it terms of the number and type of parameters. The return value of create()
is a CartBean
remote interface. This is because the CartHome
interface functions as a factory for CartBean
. (The return value for the matching ejbCreate()
method in the CartBean
class is void.)
CartBean
session bean has a remote interface Cart
that extends the EJBObject
interface. EJBObject
is a base interface for all remote interfaces. It defines the methods that enable you to
You can test if the bean object is identical to another enterprise bean object. (You can also get the primary key for an entity bean, but that doesn't apply to session beans.)
You can obtain a reference to the bean's home interface of a serialization handle to the bean instance. You can store the handle and retrieve it at a later time and then use it to regain your reference to the bean instance.
The EJBObject
interface defines the remove()
method for removing the bean instance.
Cart
remote interface defines five business methods in addition to the methods it inherits from EJBObject
. These business methods are the methods implemented in the CartBean
session bean class. The Cart
remote interface merely exposes these methods to clients. A client can call only the methods of an enterprise bean that the remote interface exposes. These are the exposed business methods:
addItem()
, which adds an item to the shopping cart.
removeItem()
, which removes an item from the shopping cart.
getTotalPrice()
, which adds the prices on all the items and returns the total price.
getContents()
, which gathers all the items in the shopping cart and returns them in a lists that can be viewed or printed.
purchaseItems()
, which attempts to purchase the items.
As you use JBuilder's Enterprise JavaBean wizard to create a session bean, JBuilder also creates a deployment descriptor for you. You can then use the Deployment Descriptor editor to customize it to your needs.
The deployment descriptor includes a set of tags and attributes whose values indicate the properties of the bean. For example, some of the tags for the CartBean
example are as follows:
<ejb-jar> <enterprise-beans> <session> <description> XML deployment descriptor cart session bean <description> <ejb-name>cart</ejb-name> <home>CartHome</home> <remote>Cart</remote> <ejb-class>CartBean</ejb-class> <session-type>Stateful</session-type> <transaction-type>Container</transaction-type> <session> <enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>cart</ejb-name> <method-name>*</method-name> </method> <trans-attribute>NotSupported</trans-attribute> </container-transaction> <container-transaction> <method> <ejb-name>cart</ejb-name> <method-name>purchase</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar>The
CartClient
program is the client application that uses the CartBean
enterprise bean. Its main()
routine includes elements that all enterprise bean client application must implement. It demonstrates how to
create()
method to create a new remote Cart object.
public static void main(String] args) throws Exception { // get a JNDI context using the Naming service javax.naming.Context context = new javax.naming.InitialContext(); Object objref = context.lookup("cart"); CartHome home = (CartHome)javax.rmi.PortableRemoteObject.narrow(objref, CartHome.class); Cart cart; { String cardHolderName = "Jack B. Quick"; String creditCardNumber = "1234-5678-9012-3456"; Date expirationDate = new GregorianCalendar(2001, Calendar.JULY,1).getTime(); cart = home home.create(cardHolderName, creditCardNumber, expirationDate); } Book knuthBook = new Book("The Art of Computer Programming", 49.95f); cart.addItem(knuthBook); ... // create compact disc and add it to cart, then list cart contents summarize(cart) cart.removeItem(knuthBook); ... // add a different book and summarize cart contents try { cart.purchase(); } catch(PurchaseProblemException e) { System.out.println("Could not purchase the items:\n\t" + e); } cart.remove(); }The
main()
routine begins by a JNDI context to look up objects. It constructs an initial context (a Java naming context). This is standard JNDI code.
main()
looks up the CartHome object called cart. Looking up a name with JNDI invoking a call from the client to the CosNaming service to look up the name in CosNaming. The CosNaming service returns an object reference to the client. In this example, it returns a CORBA object reference. The program must perform a PortableRemoteObject.narrow()
operation on the object reference and cast the returned object to the type CartHome
, and assign it to the variable home. This call is typical for distributed applications. The call uses CORBA and IIOP to do the following:
create()
parameter variables, and creates a new cart remote object.
The program creates two shopping cart items, a book and a compact disc, and adds these items to the shopping cart using the cart's addItem()
method.
The routine then lists the items current in the cart by calling the summarize()
function. summarize()
retrieves the elements or items in the cart using the cart's getContents()
method, which returns a Java Enumeration
. It then uses the Java Enumeration
interface methods to read each element in the Enumeration
, extracting the title and price for each one. Here is the summarize()
function code:
static void summarize(Cart cart) throws Exception { System.out.println("======== Cart Summary =========")' Enumeration elements = cart.getContents(); while(elements.hasMoreElements()) { Item current = (Item) elements.nextElement(): System.out.println("Price: $" + current.getPrice() + "\t" + current.getClass().getName() + " title: " + current.getTitle()); } System.out.println("Total: $" + cart.getTotalPrice()); System.out.println("==============================="); }The program then calls cart's
removeItem()
method to remove an item from the cart. It adds a different item and summarizes the cart contents again.
Finally, the program attempts to purchase the items. The purchase operation fails because it is not implemented on the server, and a PurchaseProblemException
is thrown.
Because the user is finished with the shopping session, the program removes the cart. It's not necessary to remove the cart, although it is good programming practice to do so. A session bean exists for the client that created it. When the client ends the session, the container automatically removes the session bean object. The container also removes the session bean object when it times out, although this doesn't happen immediately.
CartClient
also includes code that extends the generic Item
class with two types of items: a book and a compact disc. Book
and CompactDisc
are the classes used in the example.