Java Solutions


An Enterprise JavaBeans Skeleton Code Generator

Pat Paternostro

Here is a simple tool to automate a goodly portion of the supertedious EJB creation process, along with a nice tutorial of the EJB 1.1 specification.


EJBs (Enterprise JavaBeans) are non-visual, reusable, server-side components. For all their usefulness, however, they are difficult at worst and tedious at best to code. While you can certainly purchase an IDE (integrated development environment), such as IBM’s Visual Age for Java, to ease the pain of constructing EJBs, that avenue requires deep pockets and often times a steep learning curve. In this article, I present a utility that generates the minimal “skeleton” code required to create and package version 1.x EJBs.

EJB 1.1 Overview

EJBs simplify the development of middleware components by transparently providing support for middleware services, such as transaction management, concurrency, persistence, security, and database connectivity. These services are automatically provided via an EJB container, thus allowing developers to concentrate on the task of solving business problems. (EJB containers are execution environments, such as IBM’s WebSphere Application Server and BEA’s WebLogic Server.) EJBs provide benefits such as increased productivity, portability, and scalability.

EJBs execute in the context of an EJB container, which acts as a broker between a client and the actual bean. Clients communicate with the bean through “home” and “remote” interfaces that are implemented by the EJB container. Along with the actual bean class, developers are also responsible for coding the home and remote interfaces.

The home interface must extend the javax.ejb.EJBHome interface and is responsible for declaring the bean’s life-cycle methods including creating, finding, and removing the bean. The remote interface must extend the javax.ejb.EJBObject interface and is responsible for declaring the bean’s publicly accessible business methods whose implementations reside in the bean.

A client application uses the JNDI (Java Naming and Directory Interface) to obtain a reference to the home interface. Once acquired, the home interface’s create or find method is used to return a remote interface reference. A client application makes calls through the remote interface reference, never to the bean itself, thus allowing the container to transparently provide support services (e.g., transaction management) to the bean prior to delegating the method call to the bean (see Figure 1). The home and remote interfaces along with the container provide a layer of abstraction that achieves portability and removes the responsibility of providing middleware services from the developer.

The EJB specification defines two EJB types: SessionBean and EntityBean. (The EJB 2.0 specification defines a third EJB type, MessageDrivenBean, which is beyond the scope of this article.) Both bean types extend from the javax.ejb.EnterpriseBean interface, which is merely an empty placeholder that extends the java.io.Serializable interface.

Session Beans

Session beans are short-lived, non-persistent beans usually created to perform a specific client task. The session bean’s lifetime is defined by that of a client session. A session bean is required to implement the SessionBean interface:

public interface javax.ejb.SessionBean
    extends javax.ejb.EnterpriseBean
{
    public void ejbActivate();
    public void ejbPassivate();
    public void ejbRemove();
    public void setSessionContext
        (SessionContext ctx);
}

Session beans come in two flavors: stateless and stateful session beans. Stateless session beans are pooled and, as the name implies, do not maintain state (i.e., they typically do not contain instance variables because different bean instances can be used across method invocations). Therefore a stateless session bean can provide empty implementations for the SessionBean interface methods.

Stateful session beans are not pooled, have a one-to-one relationship with a client session, and do maintain state (i.e., they typically do contain instance variables because the same bean instance is used across method invocations). Maintaining the bean’s state is the responsibility of the EJB container. The container can swap the stateful session bean in and out of memory during periods of inactivity to minimize memory utilization. This swapping is known as passivation and activation and corresponds to the SessionBean interface methods ejbPassivate and ejbActivate respectively. The container calls the bean’s ejbPassivate method prior to swapping the bean out and saving its state. This allows the developer the opportunity to perform resource cleanup if needed (e.g., releasing a database connection). After swapping the bean back into memory and restoring its state, the container calls the bean’s ejbActivate method to give the developer the opportunity to reallocate resources if needed (e.g., restoring a database connection).

A stateless session bean’s home interface must contain a no-argument create method, whereas a stateful session bean can have more than one create method each accepting a different number of parameters. All the home interface create methods must return a remote interface reference to the created bean. In addition to the methods in the SessionBean interface, a session bean is also required to implement an ejbCreate method for every create method declared in the home interface with the same number and types of parameters. The ejbCreate methods are required to return void.

Entity Beans

Entity beans are long-lived, persistent beans usually representing business objects. An entity bean’s lifetime far exceeds that of a client session with its state maintained via persistent storage (e.g., a database). An entity bean is required to implement the EntityBean interface:

public interface javax.ejb.EntityBean extends 
    javax.ejb.EnterpriseBean
{
    public void ejbActivate();
    public void ejbPassivate();
    public void ejbLoad();
    public void ejbStore();
    public void ejbRemove();
    public void setEntityContext(EntityContext ctx);
    public void unsetEntityContext();
}

The EJB specification defines two entity bean types: CMP (container-managed persistence) and BMP (bean-managed persistence) entity beans. CMP entity beans rely on the container to provide persistence code to update the underlying data store. Therefore a CMP entity bean can provide empty implementations for the EntityBean interface methods. However, you are required to identify and map the CMP fields to database fields via a deployment tool. Moreover, the various EJB application servers have historically not done a particularly good job of implementing container-managed persistence. Though the situation is certainly improving, in practice container-managed persistence is not widely used.

BMP entity beans are required to provide persistence code to update the underlying data store. The persistence code is provided in the EntityBean interface methods ejbLoad and ejbStore. These synchronization methods are called many times by the EJB container during the BMP entity bean’s lifetime. Loading the bean involves reading data from the persistent data store and assigning that data to the bean’s attributes. Storing the bean involves writing the bean’s attribute values to the underlying data store. Don’t confuse persistence (the intent of which is to update a database) with the activation and passivation mechanisms (which swap the bean in and out of memory at more or less random times as the container needs to free up space) described earlier.

As entity beans are persistent, they require a mechanism to uniquely identify the bean to the persistent data store. That mechanism is the primary key class. Primary key classes are either single-key (e.g., Integer, Long, String) or compound-key primary keys. A compound primary key class must adhere to the following rules:

  1. The class must be public.
  2. The class must contain a default no-argument constructor.
  3. The class must implement the java.io.Serializable interface.
  4. The class must override the hashCode and equals methods.
  5. The fields must be public.

Unlike session beans, entity beans are not required to declare any create methods in the bean’s home interface. If they are declared, the methods must return a remote-interface reference. For every home interface create method declared, a corresponding ejbCreate method must be implemented in the bean with the same number and types of parameters. The ejbCreate methods are required to return a reference to the primary key. For every ejbCreate method implemented, a corresponding ejbPostCreate method with the same number and types of parameters, returning void, must also be implemented in the bean.

Although entity beans are not required to declare any home interface create methods, they are required to declare at least one finder method. The home interface must minimally declare the findByPrimaryKey method that accepts a primary key as a parameter and returns a remote-interface reference. A corresponding ejbFindByPrimaryKey method must be implemented, but only in a BMP entity bean, and it must accept a primary key as a parameter and return a primary key.

Transactions

The EJB specification defines two styles of transaction demarcation: CMT (container-managed transactions) and BMT (bean-managed transactions.) Transaction demarcation encompasses beginning and committing (or rolling back) a transaction. With CMTs, the container is responsible for providing a transactional context when executing the bean. Entity beans are required to use CMTs, whereas session beans have the choice of using either CMTs or BMTs. BMTs place the responsibility of starting and finishing transactions on the bean developer through the use of the javax.transaction.UserTransaction interface.

Though simple transactioning works reasonably well, bear in mind that EJB systems are often quite complex, involving several session beans accessing several entity beans all at once. Moreover, a purist object-oriented approach to EJBs would never access the entity beans directly, but rather access a stateless session bean and pass the session bean’s method some sort of handle to the entity bean being accessed. This way, you effectively merge the data and methods together to produce a true object. The entity bean serves the purpose of encapsulating private data in this case. When using this approach, the session bean method might have side effects (remote network connections to other servers, for example) that can make operations like rollback difficult (or impossible) to implement.

The Deployment Descriptor

An EJB 1.1 container requires an XML-based deployment descriptor, which aids the container in managing the bean. A deployment descriptor is typically created by an EJB deployment tool and includes information such as the names of the home and remote interfaces, the name of the bean class, the bean type and sub-type, transactional behavior, and security roles. A typical EJB XML-based deployment descriptor follows:

<?xml version=1.0?>
<!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.
//DTD Enterprise JavaBeans 1.1
//EN' 'http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd'>

<ejb-jar>
<enterprise-beans>
 <display-name>HelloBeanJar</display-name>
  <session>
   <display-name>HelloBean</display-name>
   <ejb-name>HelloBean</ejb-name>
   <home>com.tricomgroup.beans.session.hello.HelloHome</home>
   <remote>com.tricomgroup.beans.session.hello.Hello</remote>
   <ejb-class>com.tricomgroup.beans.session.hello.HelloBean
    </ejb-class>
   <session-type>Stateless</session-type>
   <transaction-type>Container</transaction-type>
  </session>
 </enterprise-beans>
...
</ejb-jar>

The first two tags are a standard part of all XML documents. The first tag specifies the XML version in use while the second tag specifies the DTD (Document Type Definition) that defines the document. The body of an XML document is enclosed between the beginning and ending root-element tags, in this case <ejb-jar> and </ejb-jar> respectively. All other element tags are nested within the root element tags. (A full complement of element tags is not included in the above example.)

The Generator

This brief overview covers the requirements needed to create version 1.1 EJBs. (For a more detailed discussion, consult the EJB 1.1 specification located at <http://java.sun.com/products/ejb/docs.html>.) I haven’t even touched on the security implications or the requirements needed to develop version 1.0 EJBs. Suffice it to say that changes were made between the two specifications, in particular the deployment descriptor format changed from a serialized object in EJB 1.0 to the more flexible XML-based file in EJB 1.1. The rules are many and varied and can sometimes be overwhelming to keep straight without consulting the specification or alternative documentation. That’s where the EJBSkeleton tool comes in handy.

A partial listing of the EJBSkeleton code appears in Listing 1 (the method bodies are not shown.) As you can see from Figure 2, the application is pretty intuitive. You select the desired functionality from the provided choices and click on the Generate button to generate the EJB skeleton code.

Generating EJB skeleton code requires a package name (e.g., com.tricomgroup.beans) and a base name, which enables the Generate button. Clicking the Generate button creates the home and remote interface files, the bean class file, and the primary key class file (entity beans only) whose names are derived from the specified base name. The files are created in the directory where the tool is launched and in the following directory hierarchy:

src
|_v1.0 or v1.1 (depending on version selected)
  |_<base name>
    |_<base name>.java (remote interface source file)
    |_<base name>Home.java (home interface source file)
    |_<base name>Bean.java (bean class source file)
    |_<base name>PK.java
      (primary key class source file - entity beans only)
    |_<base name>Manifest
      (EJB 1.0 deployment descriptor manifest - 
       explained below)
    |_jar
      |_<base name>BeanJar.jar
        (JAR file created when packaging beans - 
         explained below)
    |_META-INF
      |_ejb-jar.xml
        (EJB 1.1 deployment descriptor file - explained below)

To compile the generated source files, select the Compile EJB Source Files checkbox prior to clicking on the Generate button. The compiled class files are placed in the package structure specified in the Package Name field and created in the directory specified in the Root Package Directory field. If this field is left blank, the current directory is assumed.

Optionally you can package the bean by selecting the Package Bean checkbox, which is only enabled when the Compile EJB Source Files checkbox is selected. Packaging the bean involves creating a deployment descriptor file and placing the compiled class files and the deployment descriptor file in a JAR file (see directory structure above) via the JDK JAR tool. An EJB 1.0 deployment descriptor is a serialized object file that is created and placed in the same directory as the compiled class files. When packaging an EJB 1.0 bean, a JAR manifest file that identifies the location of the serialized deployment descriptor file is also created (an EJB 1.0 requirement.) This manifest file is created in the same directory as the source files. An EJB 1.1 deployment descriptor file is an XML-based file with the name ejb-jar.xml. This file is required to reside in the JAR file’s META-INF directory; therefore the tool creates the deployment descriptor file in a META-INF directory (see directory structure above.)

You have the option of adding source code to the generated skeleton files via the Add EJB Source Code button. Figure 3 shows the dialog box that’s displayed when choosing to generate a container-managed entity bean from the main window. The dialog box is separated into four sections with appropriate sections visible based on the choices made from the main window. For instance, if a stateless session bean were selected, only the EJB Source Code section would display, as the other sections don’t apply. The tool will add the source code provided in the EJB Source Code section to the bean class and will parse the source code to automatically generate the public method signatures for the remote interface. Likewise the tool also parses the Primary Key Field(s) section and the Container Managed Persistence Field(s) section as well in order to identify those variables as CMP fields in the generated deployment descriptor. CMP entity beans are required to declare the primary key fields exactly as defined in the primary key class (name included). Again the tool automatically handles this requirement, however the parsing logic is purposely simplistic and requires that each variable be declared on separate lines for both field sections. The code placed in the Add EJB Source Code dialog is saved to temporary files that are automatically deleted when the tool is exited. Therefore source code changes are preserved on each invocation of the dialog box. Finally the tool will also generate client source code when the Generate Client Source checkbox is selected. Messages detailing the completeness of the selected operations are displayed in a dialog box (see Figure 4) after the code generation is complete or immediately following an error.

Miscellaneous

Running the generator minimally requires Sun’s JDK 1.2.2 and J2EE reference implementation (available at <www.javasoft.com>). Make sure to add the J2EE.JAR and EJB10DEPLOYMENT.JAR files, located in the J2EE reference implementation LIB directory, to the CLASSPATH.

Any EJB container deployment tool should be able to read and verify the tool’s generated JAR file. The generated EJB 1.1 bean jar files were verified via Sun’s J2EE reference implementation deployment tool and the generated EJB 1.0 bean JAR files were verified via IBM’s Visual Age for Java deployment tool.

You are required to provide the database mappings for a CMP entity bean’s CMP fields via the deployment tool. The generator always creates a compound primary key class for entity beans and demarcates all bean methods as CMT methods via the deployment descriptor. You will need to provide “real” implementations for the primary key class’s equals and hashCode methods as the generator simply returns false and zero for those methods respectively.

Example

I used the tool to generate and package an EJB 1.1 stateless session bean. The generated home, remote, bean, and client source files are located in Listings 2, 3, 4, and 5 respectively. The generated XML deployment descriptor is located in Listing 6. Figure 5 displays the EJB Source Code dialog box along with the added source code. I successfully verified, deployed, and tested the bean via Sun’s J2EE reference implementation. The EJBSkeleton.java file contains the full source code for the utility. The EJBSkeleton.jar file contains all the compiled class files that comprise the utility. Both are available for download at <www.cuj.com/code>.

Conclusion

The rules are many and varied, and oftentimes overwhelming when creating EJBs. This tool greatly simplifies the construction of EJBs by keeping the rules straight and letting you concentrate on the task at hand.

References

Richard Monson-Haefel. Enterprise JavaBeans, 2nd Edition (O’Reilly & Associates, 1999).

Tom Valesky. Enterprise JavaBeans: Developing Component-Based Distributed Applications (Addison-Wesley, 1999).

Pat Paternostro is an Associate Partner with the Tri-Com Consulting Group located in Rocky Hill, CT. Tri-Com provides programming services for a wide variety of development tasks. You can reach Pat at ppaternostro@tricomgroup.com.