Advanced Java:

Internet Applications

2002 Art Gittleman

Revised by

Yong Gao

Chapter 10

Enterprise JavaBeans

This chapter has been typed in a draft mode and not formatted for publication.

Introduction

Enterprise JavaBeans (EJB) technology is part of the Java 2 Platform, Enterprise Edition (J2EE) for developing distributed applications. A J2EE server handles services such as transaction management, security, and database access so the developer can concentrate on the business logic. The J2EE server resides on a middle-tier in a three-tier architecture, between the client and the database.

EJB components, focusing on the business application, are platform independent. In contrast to the Microsoft COM+ technology that is designed for the Windows operating system, but is language independent, EJB components, written in Java, can run on any platform. Because EJB components will run on any EJB server, the developer is not locked into a proprietary application server.

Objectives:

  • Set up a J2EE server.
  • Use a tool to deploy enterprise beans.
  • Develop and deploy an entity bean.
  • Develop and deploy a session bean.
  • Use standalone, servlet, and JSP clients.

10.1. Getting Started with EJB

We introduce the J2EE architecture, set up an EJB server, and implement a Hello bean as a simple illustration.

The J2EE Architecture

In the middle-tier, a J2EE server includes an EJB container for enterprise beans, and a web container for servlets and JSP (JavaServer Pages) files. The EJB container does not allow clients to communicate directly with enterprise beans. In fact some types of beans may be shared among multiple clients. A client interacts with a bean by means of a remote interface defining the bean's business methods and a home interface defining the bean's life cycle methods.

Enterprise beans come in three varieties, entity beans, session beans, and message-driven beans. Entity beans model business objects such as a customer or an account. They have a persistent representation, usually in a database. Either the bean can manage the database interaction or the container can do it automatically.

Session beans perform operations on the business objects. They represent the client in the J2EE server, so the client can connect once with a session bean that then interacts with other beans on the server. This minimizes the connections between client and server to improve efficiency. A session bean might place an order, or reserve a flight, for example.

Session beans are not persistent. Each is associated with one client, and when the client terminates, so does the session bean. Session beans can be stateful or stateless. A stateful bean saves information so it can interact with the client. Stateless beans require no continuing interaction with the client and offer the best performance.

Message-driven beans allow asynchronous communication with the EJB server. We introduce message-driven beans in Chapter 17.

Enterprise beans are components, and may be configured as part of the process of deploying them in the EJB container. We can specify the type of transaction processing desired, and the database information for the container to manage persistence.

The steps in developing a simple EJB application are:

1. Create the enterprise bean.

Write Java programs and compile them to obtain

ProgHome.class for the Home interface

ProgRemote.class for the Remote interface

ProgEJB.class for the bean

2. Start EJB server (if not already started)

3. Deploy the enterprise bean.

Use a tool provided by the EJB container vendor to create a JAR file,

ProgEJB.jar, for the enterprise bean, and create an application

file, Prog.ear, for deployment in the EJB container. The

deployment process will create additional files needed for

communication with the clients, and a deployment descriptor.

4. Create and deploy a client.

ProgClient.class

A J2EE Server

In order to use enterprise beans, we need a J2EE server. Sun provides a reference implementation, the J2EE SDK Enterprise Edition. We use version 1.3, available from The documentation requires a second download. We need to set the JAVA_HOME and J2EE_HOME environment variables to the locations where the Java 2 SDK, Standard Edition and J2EE are installed. The J2EE version we use requires the standard edition version 1.3. The author's settings on a Windows system are:

set java_home=d:\jdk1.3

set j2ee_home=d:\j2sdkee1.3

J2EE version 1.3 implements the EJB 2.0 specification which introduced a number of changes, especially to entity beans using container-managed persistence.

The easiest way to start the server is to click on j2ee.bat in the %J2EE_HOME%\bin directory. Clicking on deploytool.bat will execute the batch file that starts the deployment tool, which pops up a GUI that we will use in our examples. One can also start the server and the deployment tool with the commands

start %j2ee_home%\bin\j2ee -verbose

start %j2ee_home%\bin\deploytool

Tip

When stopping the J2EE server use the command

%j2ee_home%\bin\j2ee -stop

to allow the server to terminate properly.

Hello Bean

Hello bean will be a stateless session bean that has one method returning a message string. We write the code for the bean and for the home and remote interfaces that allow clients to interact with it.

The remote interface has one method, hello. It extends EJBObject from the package javax.ejb. Packages whose names start with javax are standard extensions, in contrast to core packages that start with java. All methods of the remote interface must declare that they may throw a remote exception. Communication across a network must always allow for the possibility of errors.

Example 10.1 HelloRemote.java

/* Specifies business methods for Hello EJB.

*/

import javax.ejb.EJBObject;

import java.rmi.RemoteException; // Note 1

public interface HelloRemote extends EJBObject {

public String hello(String message) throws RemoteException;

}

------

Note 1: EJB uses RMI (Remote Method Invocation) for distributed object

communication. Methods that invoke a remote object using RMI must

include RemoteException in their throws clauses.

The home interface is also simple. Its purpose is to specify the lifecycle methods that create, find, and remove a bean. Because our bean is stateless, we have no variables to initialize, so our create method has no arguments. It returns a HelloRemote object, and declares that it may throw a remote exception and a create exception.

Although we declare the remote and home interfaces, the EJB container implements them. The home interface extends the EJBHome interface that has several methods that all will be implemented by the container. Similarly, the container will implement the methods of the remote interface and of EJBObject that it extends.

Example 10.2 HelloHome.java

/* Specifies methods to create, find, and remove a bean.

*/

import java.rmi.RemoteException;

import javax.ejb.CreateException;

import javax.ejb.EJBHome;

public interface HelloHome extends EJBHome {

HelloRemote create() throws RemoteException, CreateException; // Note 1

}

------

Note 1: CreateException must be included in the throws clause of all create

methods.

A session bean implements the SessionBean interface that contains four methods ejbActivate, ejbPassivate, ejbRemove, and ejbSetSessionContext. The container uses these methods to notify bean instances about lifecycle events. Our simple Hello bean does not need this information, so we implement these four methods with empty bodies.

In addition, the Hello bean implements the hello method of the HelloRemote interface, but it does not declare that it implements HelloRemote. Remember that a client does not interact with a bean directly. The container generates code that implements the HelloRemote and HelloHome interfaces, and will call the corresponding implementations in our bean class.

Example 10.3 HelloEJB.java

/* A session bean that returns a message.

*/

import javax.ejb.SessionBean;

import javax.ejb.SessionContext;

public class HelloEJB implements SessionBean {

public String hello(String message) { // Note 1

return message;

}

public HelloEJB() {}

public void ejbCreate() {} // Note 2

public void ejbRemove() {}

public void ejbActivate() {}

public void ejbPassivate() {}

public void setSessionContext(SessionContext sc) {}

}

------

Note 1: This is the implementation of the business method of the remote

interface of Example 10.1. It will be called by the container-generated

code.

Note 2: The ejbCreate method corresponds to the create method of the

home interface of Example 10.2. Each must have the same arguments.

It will be called by the container-generated code. Because we have no

fields to initialize, we use an empty body.

To compile the bean's file we use the commands

javac -classpath .;%j2ee_home%\lib\j2ee.jar

HelloRemote.java

javac -classpath .;%j2ee_home%\lib\j2ee.jar

HelloHome.java

javac -classpath .;%j2ee_home%\lib\j2ee.jar

HelloEJB.java

or

javac -classpath .;%j2ee_home%\lib\j2ee.jar Hello*.java

The Hello Application

A J2EE application may contain several beans, and web components such as servlets or JSP files. We do not add enterprise beans directly to the J2EE server, but instead package them in a J2EE application that we deploy on the server.

We use deploytool, that comes with the J2EE SDK, to package and deploy the Hello bean. First we create the J2EE application.

Stop other server if it’s running. Start j2ee server. Create d:\book3\ejb directory then copy HelloHome.class, HelloRemote.class, and HelloEJB.class into the folder.

Steps:

1. In the File menu, click on New Application

2. In the dialog that pops up, we enter Hello in the Application Name field and 3. Browse for the directory containing the files for the application. In the file dialog, we select the D:\book3\ejb directory, enter Hello.ear in the File name field

4. Click on New Application, and then on OK.

A Hello entry appears in the Local Applications panel of the deploytool GUI. We use deploytool to package our three class files composing the enterprise bean in a JAR file.

  1. In the File menu, click on New Enterprise Bean. An introductory screen pops up listing the steps involved in packaging a bean.
  2. Click on Next to get the EJB JAR dialog, which should show Hello as the application in the Enterprise will go in field.
  3. Enter HelloJAR in the Display name field
  4. Click Edit… button, and then add the HelloRemote.class, HelloHome.class, and HelloEJB.class files to the JAR.
  5. Click OK
  6. ClickNext brings us to the General screen.
  7. Select HelloEJB as the classname.
  8. Use Remote interfaces, not Local interfaces, select HelloHome as the Home interface
  9. HelloRemote as the Remote interface
  10. Enter HelloBean as the Display name
  11. Check Session Bean and Stateless
  12. Click Next, and then click Finish because we do not use the remaining screens.

This completes the packaging of Hello bean into a JAR and adding the JAR to the Hello application.

Deploying the Hello Application

The deploytool utility assists us in deploying the Hello application on the J2EE server.

  1. Click Hello in the local applications window
  2. Click JNDI tab to give our bean a name that clients will use to look it up
  3. Enter HiBean in the JNDI Name field and hit the Enter key.

JNDI is the Java Naming and Directory Interface that registers a bean using a name that clients can refer to when looking it up. To deploy Hello bean in the EJB container,

  1. Click Deploy Application in the Tools menu that brings up the Deploy Hello screen.
  2. Choose localhost as the Target Server.
  3. Check Return Client Jar displays a field to choose a name and path for the client code. We enter d:\book3\ejb\HelloClient.jar.
  4. Click Next allows us to confirm the JNDI name
  5. ClickNext again brings us to the final screen in which we click finish.

A Deployment Progress window shows the actions the server takes to deploy our bean. It creates the files in HelloClient.jar that allow a client to communicate with the Hello bean. Figure 10.1 shows the final view of the deployment tool GUI, with Hello properly installed as a server application.

Figure 10.1 The final deployment tool screen

Deploying a Client

A client must find the bean in the server. It creates a context in which the lookup proceeds. The lookup uses the JNDI name java:comp/env/ejb/ClientHello. This decouples the client from the specific bean in the container. In the deployment tool we will associate the name ClientHello that the client uses with the name HiBean that the bean uses. The lookup method returns an object that implements the home interface. Calling its create method returns an object that implements the remote interface. We call the hello method that returns the string Hello World that we pass as its argument.

To deploy HelloClient using deploytool,

Click on File, New, Application Client

Click Next on the Intro screen

Select the Hello application, add HelloClient.class,

and click Next

Select HelloClient as the main class and click Next

Click Finish.

Select HelloClient in the Hello application

Select the EJB Refs tab and press Add

Enter ejb/ClientHello as CodedName, HelloHome as the

Home interface, and HelloRemote as the Local/Remote

interface

At d:\book3\ejb, execute

SET APPCPATH=HelloClient.jar

and run the client using

%j2ee_home%\bin\runclient -client Hello.ear -name HelloClient -textauth

When prompted, enter guestor any word as the user name and guest123or any word as the password.

Example 10.4 HelloClient.java

/* Finds Hello bean and calls its hello method.

*/

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.rmi.*;

public class HelloClient {

public static void main(String[] args) {

try {

Context context = new InitialContext();

Object o = context.lookup("java:comp/env/ejb/ClientHello");

HelloHome home = (HelloHome)PortableRemoteObject

.narrow(o,HelloHome.class); //Note 1

HelloRemote remote = home.create();

System.out.println(remote.hello("Hello World"));

}catch (Exception e) {

e.printStackTrace();

}

}

}

------

Output

Initiating login ...

Username = null

Enter Username:guest

Enter Password:guest123

Binding name:`java:comp/env/ejb/ClientHello`

Hello World

Unbinding name:`java:comp/env/ejb/ClientHello`

------

Note 1: The narrow method checks that an object of a remote or abstract

interface type can be cast to a desired type. The first argument is the

object and the second argument is the desired type.

The Hello bean serves as a simple illustration. Our server and client shared the same machine, but the client could have connected remotely to the server.

Test Your Understanding

1. Which interface do we extend when defining the remote interface for a bean

that specifies the bean's business methods?

2. (Try It Yourself) Follow the steps necessary to deploy the Hello bean of

Examples 10.1, 10.2, and 10.3 and run the client of Example 10.4.

3. Explain the difference between the HelloClient.jar and

HelloClient.java files.

10.2. Entity Beans

An entity bean represents a persistent business object, often in a database. Clients may share an entity bean. Persistence means that the entity remains in the database even after the EJB container terminates.

Entity beans can either let the container manage the database accesses needed to load and store the entity (container-managed persistence), or implement the database queries itself (bean-managed persistence). Container-managed persistence requires much less code, and the code is independent of any database. But it may not allow complex representations where a business object's fields are stored in more than one table, and it can be less efficient.

In order to be independent of the database used, and to be able to persist complex objects, the EJB 2.0 specification mandates the beans using container-managed persistence be abstract, and not contain instance variables for the dtat fields. The data fields are virtual and not included in the class. There must be get and set methods for each field.

We illustrate with a container-managed Customer bean representing a customer as defined in the Customer table of the Sales database of Section 3.1. The Customer table of Figure 3.1 has CustomerID, CustomerName, Address, and BalanceDue columns. We define our remote interface to include get and set methods for the id, name, address, and due fields.

In this chapter we use the Cloudscape database system bundled with the J2EE SDK Enterprise Edition. Using container-managed persistence, Cloudscape will create the tables. In our example, in which the bean class has the name CustomerEJB, Cloudscape will name the table "CustomerEJBTable" where the quotes are part of the table name. We will use instance variables id, name, address, and due. Cloudscape adds quotes to make the column names, "id", "name", "address", and "due".

The Remote Interface

The CustomerRemote interface, representing the business operations, has methods to get and set the name, address, and due properties. We do not provide the getId and setId methods to the bean user. In this example a column in the database table represents each property, but properties could be derived values instead.

Example 10.5 CustomerRemote.java

/* Specifies business methods for Customer EJB.

*/

import javax.ejb.EJBObject;

import java.rmi.RemoteException;

public interface CustomerRemote extends EJBObject {

public String getName() throws RemoteException;

public void setName(String name) throws RemoteException;

public String getAddress() throws RemoteException;

public void setAddress(String address) throws RemoteException;

public double getDue() throws RemoteException;

public void setDue(double due) throws RemoteException;

}

------

The Home Interface