The target audience for this guide is the application assembler. The role of the application assembler is to develop a complete application using some existing Enterprise Beans. This includes the development of the client application, and the eventual development of additional Enterprise Beans.
The application assembler works with the client's view of the Enterprise Beans (i.e. the Home and Remote interfaces), and does not need to have any knowledge of their implementation. On the server side, the application assembler may define new Enterprise Beans that make use of the existing ones. Generally these new Enterprise Beans are session bean, that may be needed for several reasons:
Such session beans have a client behaviour for the existing Enterprise Beans. They must be developed as described in the Programmer's Guide. How to develop the code of the business methods that invokes the existing Enterprise Beans is explained in the section "Developing a client application", below.
It has also to be noted that a client application may involve several EJB servers, distributed transactions being automatically taken in charge. However, until XA aware JDBC drivers are available (JDBC 2.0 Standard Extension), it is not possible to perform a two phases commit on several databases.
Depending on the architecture of the application, the client part may be
each one communicating with one or several EJB servers via RMI.
A client application invokes methods on EJB Home and Remote objects. There are several ways for a client application to get an EJB object:
In the following, the different phases of a typical client application will be illustrated by the corresponding code. The example is based on the entity bean sample delivered with the platform.
Get a reference to the Home object, having its JNDI name ("AccountHome1") and the initial JNDI context (initialContext):
AccountHome home = (AccountHome) PortableRemoteObject.narrow( initialContext.lookup("AccountHome1"), AccountHome.class);
Get a reference to the account number 102:
Account a2 = home.findByNumber(102);
On this account EJB object, set the balance attribute to 100.00:
a2.setBalance(100.00);
Create a new account EJB object:
Account a1 = home.create(109, "John Smith", 0);
To start and close a transaction from the client application:
UserTransaction utx = (UserTransaction) PortableRemoteObject.narrow( initialContext.lookup("javax.transaction.UserTransaction"), UserTransaction.class); utx.begin(); ... // code of the transaction utx.commit(); // or utx.rollback();
Note: the way to obtain the object utx, implementing the UserTransaction interface on the EJB server, from a client application which is not a bean, is not specified, neither in the EJB specification, nor in the Java Transaction API specification. Therefore the way it is done in the above example is specific to JOnAS.
If a Session bean intends to demarcate transaction boundaries, then the way to do it is specified and is described in the Transactional Behaviour section of the Bean Programmer's Guide.
The handle mechanism allows a client application to maintain a reference to an EJB object. A handle object may be obtained by calling the getHandle() method on the reference to an EJB object. The main interest is that the handle class implements java.io.serializable interface, which means that a handle may be serialized. This allows the client to store the handle, or to pass it to another process. The handle may then be deserialized and used to obtain the reference to the EJB object, by calling the getEJBObject() method.
Handles on session bean objects are valid until the session bean object exists, i.e. their life time is limited to that of the client. Handles on entity bean objects are valid during the complete life time of the entity bean object; this means that such handles may be used by different clients and stored for a long time; the EJB server holding the entity bean objects may be stopped and restarted, the handle will still be valid.
If we consider the entity bean object of the example above (a2), the way to obtain a handle on this object is the following (the handle class is defined in the javax.ejb package):
Handle h = a2.getHandle();
The handle object may then be serialized and stored in a file:
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("handlefile")); out.writeObject(h); out.close();
Then, a client can read the handle, and retrieve the referenced object:
ObjectInputStream in = new ObjectInputStream(new FileInputStream("handlefile")); Handle h = (Handle) in.readObject(); Account a = (Account)PortableRemoteObject.narrow(h.getEJBObject(), Account.class);
The EJB Specification allows the client to obtain a handle for the home interface. This allows the client to store a reference to an entity bean's home interface in stable storage. The client code must use the javax.rmi.PortableRemoteObject.narrow(...) method to convert the result of the getEJBHome() method invoked on a handle to the home interface type