JAVA STEP BY STEP

Write a session EJB

Find out how EJB frees developers from the complexity of middleware development by providing complete infrastructure support

Summary
Enterprise JavaBeans gives us the perfect excuse to revisit our Forum application. EJB's ability to handle messy infrastructure issues will help us quickly replace the current RMI backend with a session bean that provides the same functionality. Because it will use the EJB container's communications, scalability, and transactions support, the ForumSessionServerBean will be surprisingly simple to write. (3,200 words)

By Michael Shoffner

Enterprise JavaBeans (EJB) 1.0 is the exciting new enterprise component model for Java. EJB is exciting because it brings modern, powerful capabilities to enterprise middleware written in Java.

No longer do you need to write every bit of infrastructure for the middleware tier of a Java application or (if you're lucky) modify previous code for this purpose. Instead, EJB handles that process for you -- all you have to do is write the actual business logic you are trying to implement.

In this article, we'll see how EJB is able to work such miracles. We'll begin with a brief background on the component software model, then we'll zero in on EJB itself. Once you have your bearings, we'll revisit the Forum application of columns past (see Resources for links to all previous Step by Step columns) and port its middleware tier to an enterprise bean.

The component software model
The component software model is based on the idea of creating reusable components that plug into containers. This model is rapidly gaining popularity in the software development community because it addresses several important development goals: reuse, high-level development focus, development automation via tools, and simplified deployment. JavaBeans, EJB, and ActiveX/COM are examples of component models.

Component models come in two basic flavors -- client-side and enterprise. Client-side component models such as JavaBeans are specialized to handle presentation and user interface issues. Enterprise component models such as EJB are concerned with providing infrastructure for transactions-oriented middleware components.

Using one of the component model specs, component developers write component "building blocks" that implement business logic. Application developers hook up these pre-built components into finished applications, which may themselves be components.

This building block approach facilitates off-the-shelf reuse of code packaged as components. Containers provide services so that component developers can write high-level business logic instead of infrastructure such as networking code. Development automation is achieved through development environments that allow the application developer to assemble components, usually using a visual metaphor.

The enterprise component model
Enterprise component models such as EJB and ActiveX/MTS bring the component model of development to middleware. Enterprise middleware development is notoriously complicated -- it involves not only business logic, but concurrency and scaling issues, as well as gluing together incompatible systems on incompatible platforms.

Enterprise component models solve middleware development complexity by factoring all of this infrastructure into containers and servers. This allows the middleware developer to focus on writing the business logic, without having to worry about synchronization, scalability, transaction integrity, networking, distributed object frameworks, and other related matters.

In other words, the enterprise component model offers developers the following advantages:

EJB: An overview
An EJB runtime environment is composed of a server and a set of containers. The server is not an application server; instead, it routes method calls to the enterprise beans deployed under its containers and provides services to these containers and their components.

The services provided are defined by contracts between the various parts of the EJB architecture, such as the contract that exists between the container and the beans in it. These contracts provide interfaces that decouple parts of the architecture into roles.

EJB roles
The EJB specification defines a number of roles necessary in implementing the EJB component architecture. The roles are logical in nature, so multiple roles may in fact be performed by the same party. Here's a brief look at the roles EJB defines:

Server provider
The server provider provides the EJB server, which handles distributed object, distributed transactions management, and other services for enterprise beans in containers. Examples of server providers are OS, database, and middleware vendors.

The interface between server and container is vendor-specific in EJB 1.0. A server vendor usually provides containers for use with its EJB server.

Container provider
The container provider produces a container, which is the context that interfaces with enterprise beans at runtime. The container can implement the session bean contract or the entity bean contract. We'll discuss these contracts later on.
The container provider also makes tools available for the deployer to use in deploying enterprise beans in the runtime environment. In many cases the server provider also acts as the container provider.
Enterprise bean provider
The Enterprise bean provider writes enterprise beans to make up specific applications. The provider must produce several necessary items (see The Enterprise bean provider) and bundle them into an ejb-jar, which is the file packaging structure for an enterprise bean. The packaged bean then goes to the deployer and/or application assembler.
Deployer
The deployer takes beans produced by the enterprise bean provider and deploys them in the backend runtime environment. This process may involve mapping the security roles set by the beans to the security roles required by the organization.
The deployer may also customize the functionality of an enterprise bean by writing a wrapper for its business methods using container tools.
Application assembler
The application assembler uses the client view contract of the enterprise beans deployed at the backend to assemble client applications. The application assembler may also produce new beans by combining existing beans.

The diagram below illustrates EJB roles and deployment.


The flow starts with the EJB provider, which creates the bean and makes it available to application assemblers and EJB deployers. A deployer installs the bean onto a runtime node, which already has an EJB server and container(s) provided by the server and container provider, respectively.

Session beans vs. entity beans
There are two types of enterprise Java beans: session and entity.

A session enterprise bean models a connection, or session, with a single client. Session beans persist only for the life of the connection with the client. If the EJB server crashes, the session bean dies. A bean must implement the interface javax.ejb.SessionBean to be a session bean.

When a new client references a session bean from the server, the container creates a new instance of the session bean, which is tied to the client that made the reference request through a bean object provided by the container. The session bean may then act on data in a database in some way, including taking part in transactions.

Entity beans model business objects that need to persist beyond the life of a client instance. Each instance of an entity bean can be accessed by multiple clients simultaneously. Entity beans survive crashes of the server. A bean must implement the interface javax.ejb.EntityBean to be an entity bean.

The Enterprise bean provider
When we convert the Forum backend into a bean, we will be acting in the role of bean provider.

The EJB provider has to adhere to two contracts: the client contract and the component contract. The client contract is the view that the client sees of the bean. The component contract is the relationship between the bean and the container.

The following are produced by the bean provider to implement the provider's responsibilities with respect to these contracts:

Porting the Forum server to EJB
In our last encounter with the discussion forum application, we implemented its server as an RMI server.

This month, we're going to implement the server side as a session EJB. The first step in this process is to set up the EJB development environment.

Setting up the EJB development environment

Setting up the EJB development environment is fairly straightforward:

  1. Download the EJB and JNDI classes (see Resources )
  2. Set up the EJB classes

    The files unpack as javax/ejb and so can be put directly into the project directory. You can also add them to the classpath if you prefer.

  3. Set up the JNDI files

    Create a directory called jndi in the project directory and put lib/ and examples/ from the JNDI zip file into it.

  4. Set up your CLASSPATH to see the JNDI classes

    The JNDI classes are contained in lib/jndi.jar.

  5. Set up the documentation (optional)

Now that the development environment is set up, it's time to do convert the Forum. The diagram depicts what the ForumSessionServer bean will contain in its ejb-jar file.


An EJB contains two interface files and one class file in its ejb-jar file. The ForumSessionServerHome interface extends the javax.ejb.EJBHome interface, the ForumSessionServer extends the javax.ejb.EJBObject interface, and the ForumSessionServerBean implements the javax.ejb.SesionBean interface.

Writing the remote interface
ForumSessionServer (the EJB remote interface) defines all the business methods of the bean, as shown in the figure below.

The following are the requirements for the remote interface:

import java.util.*;
import java.rmi.*;

interface ForumSessionServer extends javax.ejb.EJBObject {
  // from Forum 1.0 API interface
  Hashtable loadAllThreads () throws RemoteException;
  Vector loadThreadArticles (String t) throws RemoteException;
  boolean postArticle (String art, String t) throws RemoteException;
}

Writing the home interface
ForumSessionServerHome (the EJB home interface) provides the client with methods to create an instance of the bean and retrieve a remote reference to it. These methods are all called create. The requirements for this interface are as follows:

import java.rmi.*;
import javax.ejb.*;

interface ForumSessionServerHome extends EJBHome {
  public ForumSessionServer create (String d, String db, String u, String p,
  String t) throws RemoteException, CreateException;
}

Writing the ForumSessionServerBean class
The EJB bean class, ForumSessionServerBean, provides the implementation for the business methods that the client can call. It uses the services provided by the container to handle requests from the client. The container also provides a SessionContext object and notifications of certain events.

The requirements for the bean implementation class are:

The bean class can also implement the javax.ejb.SessionSynchronization interface, which provides notifications regarding the state of a transaction containing a business method.

import java.util.*;
import java.sql.*;
import javax.ejb.*;

public class ForumSessionServerBean implements SessionBean {

  SessionContext sessionContext;
  String driver, dbURL, user, passwd, tableName;

  // SessionBean methods
  public void setSessionContext (SessionContext sc) {
    // called first by container after Class.newInstance ()
    this.sessionContext = sc;
  }

  public void ejbRemove () {
    // called before container removes bean instance
  }

  public void ejbActivate () {
    // called after bean is activated to allow resource setup
  }

  public void ejbPassivate () {
    // called before bean is passivated to allow resource cleanup
  }

Here we see the SessionBean methods that are required of all session beans. The setSessionContext() method is called by the container immediately after the new bean instance is created. The SessionContext is passed into the bean instance with this call.

The ejbRemove() method is called by the client when it is through with a bean. If the client never calls this method for some reason, the container has the option of removing the EJB instance itself after some timeout period.

The ejbActivate() and ejbPassivate() methods are used by the container to notify the bean that it is about to be taken out of or put into secondary storage, respectively.

  // ForumSessionServerHome method
  public void ejbCreate (String d, String db, String u, String p, String t) {
    // called second by container
    this.driver = d;
    this.dbURL = u;
    this.passwd = p;
    this.tableName = t;
  }

  // ForumSessionServer business methods
  Hashtable loadAllThreads () {
    // open db connection
    // load threads from db
    // close db connection
    // return a Hashtable with the threads and empty Vectors
  }

  Vector loadThreadArticles (String t) {
    // open db connection
    // load articles from thread t from db
    // close db connection
    // return a Vector with all the articles from thread t
  }

  boolean postArticle (String art, String t) {
    // open db connection
    // post article on thread t to the database
    // close db connection
    return true;
  }
}

The method of ForumSessionServerHome is the single create (...) method. This method can be overloaded to accept any number of arguments. These arguments are used to pass initial "conversational state" into the client's bean object.

The business methods should be filled in with database-specific code. Note that a session EJB does not keep permanent state information as an entity EJB does. The session bean is visible only to the client that creates it and is (eventually) removed when its client goes away.

Now that the bean code is defined, it should be compiled into class files for deployment packaging.

The deployment descriptor
The deployment descriptor provides details on EJB deployment to the runtime container. The descriptor is a serialized instance of javax.ejb.deployment.SessionDescriptor. EJB provider tools typically handle the task of creating the serialized deployment descriptor. However, you can do it manually by writing a mini-application that creates an instance of the deployment descriptor and serializes it to the filesystem.

The deployment descriptor instance has its session timeout set to a timeout value, or 0, to indicate that the container should use a container default timeout. It also has its StateManagementType set to STATEFUL_SESSION or STATELESS_SESSION, depending on whether or not the bean keeps state in instance variables.

For the ForumSessionServer bean, we call the following methods on our deployment descriptor instance:

deploymentDescriptor.setSessionTimeout (0);
deploymentDescriptor.setStateManagementType (SessionDescriptor.STATELESS_SESSION);

Once these values are set, the deployment descriptor instance should be serialized to a file. The serialized deployement descriptor for the ForumSessionServer should be called ForumSessionServerDeployment.ser.

Packaging the ForumSessionServer EJB
The final step for the bean provider is to package the ForumSessionServer EJB into an ejb-jar file for deployment.

The ejb-jar file contains a manifest file that identifies the EJBs included in the file. The manifest file must be named META-INF/MANIFEST.MF. The format of the manifest file for the ForumSessionServer is the following, with the Name: field set to the name of the deployment descriptor:

Name: ForumSessionServerDeployment.ser
Enterprise-Bean: True

The two interface files and the bean class file go into the ejb-jar, along with the deployment descriptor and a serialized Properties object, if one is needed. The Properties object has key/value pairs that represent any environment properties that the bean will need when it is instantiated by the container. Our ForumSessionServerBean doesn't require a Properties object.

All that's left is to create the ejb-jar file (use the jar utility) and the bean is completely packaged and ready to be deployed.

Deployment to the EJB container
The person acting as EJB deployer will deploy the ejb-jar file to the EJB server node. The EJB container tools, provided by the container vendor, will generate the support classes necessary to do this.

Using the ForumSessionServer in the Forum client
Recall that each client instance of the Forum consists of two primary objects -- a Forum, which is a Frame, and an associated communications object. The Forum contains the GUI and handles user events, and the ForumComm implements the actual networking tasks involved with talking to the server.

The Forum client essentially needs only to replace its RMI lookup code with JNDI code to find the ForumSessionServer:

// props is a Properties that contains the server location and type of context
Context context = new InitialContext (props);
ForumSessionServerHome fssh;
fssh = (ForumSessionServerHome) context.lookup("apps/ForumSessionServer");
ForumSessionServer server;
server = fssh.create ("driver", "location", "pass", "tablename");

The new code goes in ForumComm in place of the RMI code that is already there.

When the client is ready to shut down, it should remove the ForumSessionServer bean object from the server:

server.remove ();

Conclusion
As you can see, writing a session bean is pretty easy. Thanks to the support that the container and server provide, you are not responsible for writing networking, synchronization, transaction management, or any other infrastructure to support the bean's business logic. The work to produce the original RMI implementation was far more tedious! In addition, you can deploy the ForumSessionServer EJB on any node running an EJB server. You can also provide it to a third party for use as a building block in an application.

You can apply the techniques used in creating the Forum EJB to projects of your own if the backend has session-like characteristics. You can also use entity EJBs, which are a bit more complicated, to model objects that represent permanent entities. In either case, writing to EJB confers numerous advantages over more "old fashioned" ways of writing applications.

About the author

The software industry is a strange world, where the only real sanctuary is to be quick or be dead. Fear of the dark can make you rue the evil that men do and all the wasted years. Sometimes it seems that the iron maiden would be kinder. But Michael, like thousands of his fellow developers, tries his best every day to be a trooper and fly where eagles dare.

Resources

Information about EJB

EJB development libraries and documentation

Previous Step by Step articles

(c) Copyright 1998 Web Publishing Inc., an IDG Communications company

Feedback: jweditors@javaworld.com
Technical difficulties: webmaster@javaworld.com
URL: http://www.javaworld.com/jw-07-1998/jw-07-step_p.html
Last modified: Thursday, July 01, 1999