The following sections describe the client application SortClient.java
, that calls the sample SortBean
session bean. SortBean
is a stateless session bean that implements a merge/sort algorithm. Here is the code of SortClient
:
// SortClient.java ... public class SortClient { ... public static void main(String[] args) throws Exception { javax.naming.Context context; { // get a JNDI context using the Naming service context = new javax.naming.InitialContext(); } Object objref = context.lookup("sort"); SortHome home = (SortHome) javax.rmi.PortableRemoteObject.narrow(objref, SortHome.class); Sort sort = home.create(); ... //do the sort and merge work sort.remove(); } }
SortClient
imports the required JNDI classes and the SortBean
home and remote interfaces. The client uses the JNDI API to locate an enterprise bean's home interface. First the client must obtain a JNDI initial naming context. The code for SortClient
instantiates a new javax.naming.Context
object, which is called InitialContext
. The client then uses the context lookup()
method to resolve the name to a home interface.
The context's lookup()
method returns an object of type java.lang.Object
. Your code must cast this returned object to the expected type. The SortClient
code shows a portion of the client code for the sort example. The main()
routine begins by using the JNDI naming service and its context lookup()
method to locate the home interface. You pass the name of the remote interface, which in this case is sort
, to the context.lookup()
method. Note that the program eventually casts the results of the context.lookup()
method to SortHome
, the type of the home interface.
create()
method, so that is the one the client must call to obtain the remote interface. The default create()
method has no parameters. So for the SortClient
code sample, the call to the get the remote interface looks like this:
Sort sort = home.create();
The cart example discussed in "Developing session beans," on the other hand, uses a stateful session bean, and its home interface, CartHome
, implements more than one create()
method. One of its create()
methods takes three parameters, which together identify the purchaser of the cart contents, and returns a reference to the Cart
remote interface. The CartClient
sets values for the three parameters—cardHolderName
, creditCardNumber
, and expirationDate
—then calls the create()
method. Here's the code:
Cart cart; { String cardHolderName = "Jack B. Quick"; String creditCardNumber = "1234-5678-9012-3456"; Date expirationDate = new GregorianCalendar(2001, Calendar.JULY, 1).getTime(); cart = home.create(cardHolderName, creditCardNumber, expirationDate); }
A client uses a find operation to locate an existing entity object, such as a specific row within a relational database table. That is, find operations locate data entities that have previously been inserted into data storage. The data might have been added to the data store by an entity bean, or it might have been added outside of the EJB context, such as directly from within the database management system (DBMS). Or, in the case of legacy systems, the data might have existed prior to the installation of the EJB container.
A client uses an entity bean object's create()
method to create a new data entity that will be stored in the underlying database. An entity bean's create()
method inserts the entity state into the database, initializing the entity's variables according to the values in the create()
method's parameters.
Each entity bean instance must have a primary key that uniquely identifies it. An entity bean instance can also have secondary keys that can be used to locate a particular entity object.
findByPrimaryKey()
, which locates the entity object using its primary key value. This is its signature:
<remote interface> findByPrimaryKey(<key type> primaryKey)Each entity bean must implement a
findByPrimaryKey()
method. The primaryKey
parameter is a separate primary key class that is defined in the deployment descriptor. The key type is the type for the primary key, and it must be a legal value type in RMI-IIOP. The primary key class can be any class, such as a Java class or a class you've written yourself.
For example, suppose you have an Account
entity bean for which you've defined the primary key class AccountPK
. AccountPK
, a String
type, holds the identifier for the Account
bean. To obtain a reference to a specific Account
entity bean instance, set the AccountPK
to the account identifier and call the findByPrimaryKey()
method as shown here:
AccountPK accountPK = new AccountPK("1234-56-789"); Account source = accountHome.findByPrimaryKey(accountPK);
Bean providers can define additional finder methods that a client can use.
Keep in mind that an entity bean exists for as long as data is present in the database. The life of the entity bean isn't bound by the client's session. The entity bean can be removed by calling one of the bean's remove methods. These methods remove the bean and the underlying representation of the entity data from the database. It's also possible to directly delete an entity object, such as by deleting a database record using the DBMS or with a legacy application.
For example, the following is some code from a client that accesses the cart session bean. The code shown here begins from the point where it has created a new session bean instance for a card holder and retried a Cart
reference to the remote interface. The client is ready to invoke the bean methods:
... Cart cart; { ... // obtain a reference to the bean's remote interface cart = home.create(cardHolderName, creditCardNumber, expirationDate); } // create a new book object Book knuthBook = new Book("The Art of Computer Programming", 49.95f); // add the new book item to the cart cart.addItem(knuthBook); ... // list the items currently in the cart summarize(cart); cart.removeItem(knuthBook); ...First the client creates a new book object, setting its
title
and price
parameters. Next it invokes the enterprise bean business method addItem()
to add the book object to a shopping cart. The CartBean
session bean defines the addItem()
method, and the the Cart
remote interface makes it public. The client adds other items (these aren't shown here), then calls its own summarize()
method to list the items in the shopping cart. This is followed by the remove()
method to remove the bean instance. Note that a client calls the enterprise bean methods in the same way that it invokes any method, such as its own summarize()
method.
remove()
method operates differently for session beans than it does for entity beans. Because a session object exists for one client and isn't persistent, a client of a session bean should call the remove()
method when it's finished with a session object. Two remove()
methods are available to the client: the client can remove the session object with the javax.ejb.EJBObject.remove()
method, or the client can remove the session handle with the javax.ejb.EJBHome.remove(Handle handle)
method. For more information on bean handles, see "Referencing a bean with its handle."
While it isn't required that a client remove a session object, it's good programming practice. If a client doesn't remove a stateful session bean object, the container will eventually remove the object after a certain time, specified by a timeout value. The timeout value is a deployment property. A client can also keep a handle to the session for future reference, however.
Clients of entity beans don't have this problem as entity beans are associated with a client only for the duration of a transaction and the container is in charge of their life cycles, including their activation and passivation. A client of an entity bean calls the bean's remove()
method only when the entity object is to be deleted from the underlying database.
You can use the remote interface handle to recreate only the reference to the bean, however. You can't use it to recreate the bean itself. If another process has removed the bean, or the system removed the bean instance, then an exception is thrown when the client tries to use the handle to reestablish its reference to the bean.
When you aren't sure that the bean instance will still be in existence, rather than using a handle to the remote interface, you can store the bean's home handle and recreate the bean object later by invoking the bean's create or finder method.
After the client creates a bean instance, it can use the getHandle()
method to obtain a handle to this instance. Once it has the handle, it can write it to a serialized file. Later, the client program can read the serialized file, casting the object that it reads in to a Handle
type. Then, it calls the getEJBObject()
method on the handle to obtain the bean reference, narrowing the results of getEJBObject()
to the correct type for the bean.
For example, the CartClient
program might do the following to use a handle to the CartBean
session bean:
import java.io; import javax.ejb.Handle; ... Cart cart; ... cart = home.create(cardHolderName, creditCardNumber, expirationDate); // call getHandle() on the cart object to get its handle cartHandle = cart.getHandle(); // write the handle to serialized file FileOutputStream f = new FileOutputStream ("carthandle.ser"); ObjectOutputStream o = new ObjectOutputStream(f); o.writeObject(myHandle); o.flush(); o.close(); ... // read handle from file at later time FileInputStream fi = new FileInputStream ("carthandle.ser"); ObjectInputStream oi = new ObjectInputStream(fi); //read the object from the file and cast it to a Handle cartHandle = (Handle)oi.readObject(); oi.close(); ... // Use the handle to reference the bean instance Cart cart = (Cart) javax.rmi.PortableRemoteObject.narrow(cartHandle.getEJBObject(), Cart class); ...When it's finished with the session bean handle, the client can remove it by calling the
javax.ejb.EJBHome.remove(Handle handle)
method.
When a client manages its own transactions, it's responsible for delimiting the transaction boundaries. That is, it must explicitly start the transaction and end (commit or roll back) the transaction.
A client uses the javax.transaction.UserTransaction
interface to manage its own transactions. It must first obtain a reference to the UserTransaction
interface, using JNDI to do so. Once it has the UserTransaction
context, the client uses the UserTransaction.begin()
method to start the transaction, followed later by the UserTransaction.commit()
method to commit and end the transaction (or UserTransaction.rollback()
to rollback and end the transaction). In between, the client accesses EJB objects and so on.
The code shown here demonstrates how a client would manage its own transactions; the code that pertains specifically to client-managed transactions are highlighted in bold:
... import javax.naming.InitialContext; import javax.transaction.UserTransaction; ... public class clientTransaction { public static void main (String[] argv) { InitialContext initContext = new InitialContext(); UserTransaction ut = null; ut = (UserTransaction)initContext.lookup("java:comp/UserTransaction"); // start a transaction ut.begin(); // do some transaction work ... // commit or rollback the transaction ut.commit(); // or ut.rollback(); ... } }
For more information about transactions, see the chapter "Managing transactions."
getMetaData()
method.
The getMetaData()
method is most often used by development environments and tool builders that need to discover information about an enterprise bean, such as for linking together beans that have already been installed. Scripting clients might also want to obtain metadata on the bean.
Once the client retrieves the home interface reference, it can call its getEJBMetaData()
method. Then, the client can call the EJBMetaData
interface methods to extract such information as this:
EJBHome
home interface, using the EJBMetaData.getEJBHome()
method.
EJBMetaData.getHomeInterfaceClass()
method.
EJBMetaData.getRemoteInterfaceClass()
method.
EJBMetaData.getPrimaryKeyClass()
method.
EJBMetaData.isSession()
method. The method returns true
if this is a session bean.
EJBMetaData.isStatelessSession()
method. The method returns true
if the session bean is stateless.
EJBMetaData
interface in its entirety:
package javax.ejb; public interface EJBMetaData { EJBHome getEJBHome(); Class getHome InterfaceClass(); Class getRemoteInterfaceClass(); Class getPrimaryKeyClass(); boolean isSession(); boolean isStatelessSession(); }
Your client is likely to call multiple beans, however, so you'll have to perform these steps in your client code for other beans it accesses. And you'll add the calls that access the business logic of the enterprise beans to your client code yourself.
For more information on using the EJB Test Client wizard, see "Creating a test client application."