Enterprise JavaBeansTM
Working with Entity and Session Beans

By Monica Pawlan

Today, more and more developers want to write distributed transactional applications for the enterprise, and leverage the speed, security, and reliability of server-side technology. One approach is to use a multitiered model where a thin-client application invokes business logic that executes on the server.

Normally, thin-client multitiered applications are hard to write because they involve many lines of intricate code to handle transaction and state management, multithreading, resource pooling, and other complex low-level details. The Enterprise JavaBeansTM (EJB) architecture makes these applications easy to write because it separates the low-level details from the business logic. You concentrate on creating the best business solution and leave the rest to the underlying architecture.

To show you how it works, this article walks through a very simple web-based application where the thin-client is a servlet. The servlet invokes enterprise Beans for database reads and writes and to perform a simple calculation.

Enterprise Beans Defined

An enterprise Bean is a body of code with fields and methods to implement modules of business logic. Client programs interact with one or more Beans, and an enterprise Bean can be implemented to interact with other enterprise Beans. An enterprise Bean is a building block that can be used alone or with other enterprise Beans to build a complete and robust thin-client multitiered application.

There are two types of enterprise Beans: session Beans and entity Beans. An enterprise Bean that implements a business task is a session Bean, and an enterprise Bean that implements a business entity is an entity Bean.

  • A session Bean represents a transient conversation with a client, and might execute database reads and writes, but it is not required. A session Bean might invoke the JDBC calls itself or it might use an entity Bean to make the call, in which case the session Bean is a client to the entity Bean. A session Bean's fields contain the state of the conversation and are transient. If the server or client crashes, the session Bean is gone. This model is typically used with database programming languages such as PL/SQL.
  • An entity Bean represents data in a database and the methods to act on that data. In a relational database context for a table of employee information, there is one Bean for each row in the table. Entity Beans are transactional and long-lived. As long as the data remains in the database, the entity Bean exists. This model can be easily used for relational databases and is not restricted to object databases.
Session Beans Entity Beans
Fields contain conversaton state. Represents data in a database.
Handles database access for client. Shares access for multiple users.
Life of client is life of Bean. Persists as long as data in database.
Can be transaction aware. Transactional.
Does not survive server crashes. Survives server crashes.

Note: In the Enterprise Java Beans specification, EJB Server support for session Beans is mandatory. EJB Server Support for entity Beans is currently optional, but becomes mandatory for version 2.0 of the specification.

Simple Example

A high-level view of the simple example application is shown in the diagram. The client application is a servlet that receives data from and sends data to a browser, and interacts with an entity Bean and a session Bean through their home and remote interfaces. The EJB Home Server handles all the low-level details including the database read and write operations.

  • An enterprise Bean's remote interface describes the Bean's methods, or what the Bean does. A client program or another enterprise Bean calls the methods defined in the remote interface to invoke the business logic implemented by the Bean.
  • An enterprise Bean's home interface describes how a client program or another enterprise Bean creates, finds, and removes that enterprise Bean from its container.
  • The container, shown in light blue (cyan), provides the interface between the enterprise Bean and the low-level platform-specific functionality that supports the enterprise Bean.

You do not need to know how an enterprise Bean is implemented to use it; all you need to know are its methods. You might or might not write your own enterprise Beans to use in an application. It is possible and often desirable to use enterprise Beans written by a provider that you assemble into an application.

Deployment tools and an EJB Home Server are essential to running the application code. The deployment tools generate enterprise Bean containers, which are classes that provide an interface to the low-level implementations in a given EJB Server. The server provider can include containers and deployment tools for their server and will typically publish their low-level interfaces so other vendors can develop containers and deployment tools for their server.

The simple example uses the EJB Server created by EJBHome. Visit this site for a free reference implementation that includes the EJB Server and deployment tools for generating containers. The site also provides tutorials to walk you through example programs that come with the download.

Source Code

The source code files for the example are listed below. The example program requires a database table named bonus with the following fields:

  CREATE TABLE BONUS 
    SOCSEC       Integer,
    BONUS        Real,
    primary key  (SOCSEC)

The source code follows naming conventions so the EJB Home Server can find the application classes, containers, and database table. For example with The source for a given enterprise Bean, the enterprise Bean, home interface, and primary key class names use the remote interface name as a prefix.

Other naming conventions are used within the source code and discussed below where they appear. While source file-naming conventions are standard across EJB Server implementations, naming conventions used within the source are specific to the EJB Server or deployment tool you use.

Client Program

Entity Bean

  • Bonus.java, the remote interface with these methods:
    • getBonus
    • getSocSec
    • addBonus
  • BonusHome.java, the home interface with these methods:
    • create
    • findByPrimaryKey
  • BonusBean.java, an enterprise Bean with these public fields and methods:
    • int bonus
    • int socsec
    • getBonus
    • getSocSec
    • addBonus
    • ejbCreate
  • BonusPK.java, primary key with these fields and methods:
    • socsec
    • BonusPK

Session Bean

  • Calc.java, the remote interface with this method:
    • calcBonus
  • CalcHome.java, the home interface with this method:
    • create
  • CalcBean.java, an enterprise Bean with these public fields and methods:
    • int bonus
    • int calcBonus
    • ejbCreate

Container Classes

When the entity and session Beans are deployed, a number of container source and class files are generated with the following prefixes. A container is a set of classes generated by the deployment tool that manages an enterprise Bean's persistence, transactional properties, and security.

  • EJBHomeBonus*.java
  • EJBHomeBonus*.class
  • EJBHomeCalc*.java
  • EJBHomeCalc*.class

Client Program

The thin-client BonusServlet.java declares variables and parameter values of specific types to locate the database table, create the home interface, and invoke the entity and session Bean methods.


Note: To keep the code simple, data values that the servlet would normally receive from user input to a browser form is hard coded.


These are the import and declarations statements. The entity Bean remote interface type is Bonus and maps to the database table name, which is also Bonus. The socsec and bonus variables map to the fields in the database table. Variable names that map to the database table or fields in the database are case insensitive.

  import javax.servlet.*;
  import javax.servlet.http.*;
  import java.io.*;
  import java.util.Properties;
  import javax.naming.*;
//location of Bean classes
  import com.ejbhome.examples.*;

  public class BonusServlet extends HttpServlet {

//Entity Bean home and remote interface variables
    BonusHome homebonus;
    Bonus theBonus, rec1;

//Session Bean home and remote interface variables
    CalcHome homecalc;
    Calc theCalculation;

    int socsec = 0, retsocsec = 0;
    int bonus = 0, retbonus = 0;

The EJB Home Server uses the beans.properties configuration file to map enterprise Beans to the home interfaces for their respective container classes. Here is how the mapping looks. The container classes are not created until the Beans are deployed, but you can put the entry into this file before you deploy because the naming convention is consistent. The values calcs and bonuses are used in the next code segment for the enterprise Bean lookup. The values in this file and the strings used in the code have to match exactly so the EJB Home Server can look up the enterprise Bean home interface.

calcs=com.ejbhome.examples.EJBHomeCalcHome
bonuses=com.ejbhome.examples.EJBHomeBonusHome

Here is the servlet init method implementation. The JNDI API is used to look up the Beans and containers.

  public void init(ServletConfig config) 
			throws ServletException{
    try{
        Properties env = new Properties();
        env.put("java.naming.factory.initial", 
		"com.ejbhome.naming.spi.rmi.RMIInitCtxFactory");
        Context ctx = new InitialContext(env);
//Look up home interfaces and containers 
//for entity and session beans. 
//Strings map to settings in the beans.properties file. 
        homebonus = (BonusHome)ctx.lookup("bonuses");
        homecalc = (CalcHome)ctx.lookup("calcs");       

   } catch (Exception NamingException) {
        NamingException.printStackTrace();
   }
  }

In the next code segement, the socsec and bonus variables are initialized with values that would normally come from user input to a form in the browser. These values are used to create the entity Bean home interface and two records in the Bonus table. After each record is created, its data is retrieved from the database and displayed in the browser. For simplicity, the code to display the data in the browser is not included in the segment, but here is the entire source file for the BonusServlet.java servlet.

   try{
        socsec = 555220000;
        bonus = 200;

        for(int i = 1; i <3; i++){ //Use the entity Bean home interface to create a record theBonus="homebonus.create(socsec," bonus); //Get the data from the record and display it in the browser retbonus="theBonus.getBonus();" retsocsec="theBonus.getSocSec();" socsec +="1;" } } catch (Exception CreateException) { CreateException.printStackTrace(); } 
This next code segment uses the primary key class to retrieve a record from the database, and uses the home interface to retrieve the data in the record fields. For simplicity, the code to display the retrieved data in the browser is not included in the segment, but here is the entire source file for the BonusServlet.java servlet.
   try{
//Instantiate a primary key object
        BonusPK PK = new BonusPK(555220000); 
//Locate a record with the primary key
        rec1 = hmebonus.findByPrimaryKey(PK);
//Use the entity Bean home interface 
//to retrieve current bonus value
        retbonus = rec1.getBonus();

This next code segment creates the session Bean's home interface, and uses the home interface to call the session Bean's calcBonus method. The hard-coded values passed to the calcBonus method would normally be received by user input to a form in the browser. For simplicity, the code to display the final bonus in the browser is not included in the segment, but here is the entire source file for the BonusServlet.java servlet.

//Calculate bonus
        int base = 100; 
        int perf=5, company=2;
        theCalculation = homecalc.create();
        int calc = theCalculation.calcBonus(
				base, perf, company);       
        System.out.println(calc);
        rec1.addBonus(calc);
        retbonus = rec1.getBonus();
   } catch (Exception FinderException) {
        FinderException.printStackTrace();
   }

Running the Application

The thin-client servlet produces the following output. Of course, you need the entity and session Beans compiled and deployed before the application will actually work. The next sections describe the source files for the enterprise Beans and enterprise Bean deployment.

Record 1

Soc Sec: 555220000
Bonus Total: 200

Record 2

Soc Sec: 555220001
Bonus Total: 200

Calculate Bonus for 555220000

Bonus Before: 200
Bonus After: 1200

Entity Bean Source Code

The example entity Bean represents a row in the Bonus table. At runtime, there can be any number of simultaneous entity Bean instantiations to represent different rows in the table. The thin-client servlet instantiates two entity Beans to create the two rows in the Bonus table.

Bonus Table
socsec (Primary Key) bonus
555220000 200
555220001 200

However, the thin-client servlet does not work directly with the entity Bean to create rows or access data, but creates an instance of the home interface. The home interface extends EJBHome and has methods that define how the entity Bean is created and located in its container. It also follows the rules of the Remote Method Invocation (RMI) API in that the arguments and return types for each method must be serializable and the methods should throw java.rmi.RemoteException as one of its exception.

package com.ejbhome.examples;

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

public interface BonusHome extends EJBHome {
  Bonus create(int bonus, int socsec) 
		throws CreateException, RemoteException;
  Bonus findByPrimaryKey(BonusPK socsec) 
		throws FinderException, RemoteException;
}

When the home interface is instantiated, the EJB Home Server also creates the remote interface and enterprise Bean instances. Here is the remote interface. It extends EJBObject and declares the BonusBean methods. It also follows the rules of the RMI API in that the arguments and return types for each method must be serializable and the methods should throw java.rmi.RemoteException as one of its exception.

package com.ejbhome.examples;

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

public interface Bonus extends EJBObject {
  int getBonus() throws RemoteException; 
  int getSocSec() throws RemoteException;
  void addBonus(int bonus ) throws RemoteException;
}

The EJBHome server requires a container-managed entity Bean to have a primary key class with a public primary key field (or fields, if using composite primary keys). You can have the container manage an enterprise Bean or write the code to manage the Bean yourself. In this example, both Beans are container-managed, and you should always let the container manage an entity Bean.

Here is the primary key class. The primary key in the Bonus table is socsec, and so socsec is a public field in this class that is assigned a value when the class is constructed.

package com.ejbhome.examples;

public class BonusPK implements java.io.Serializable {
  public int socsec;

  public BonusPK(int socsec) {
    this.socsec = socsec;
  }

  public BonusPK() {}
}

Now for a look at the entity bean source code. It implements EntityBean and the developer-defined and interface methods. It should follow the rules of the RMI API in that the arguments and return types for each method must be serializable and the methods should throw java.rmi.RemoteException as one of its exception.

package com.ejbhome.examples;

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

public class BonusBean implements EntityBean {

  public int bonus = 0;
  public int socsec = 0;
  protected EntityContext ctx;

  public int getBonus() throws RemoteException {
        return bonus;
  }
  public int getSocSec() throws RemoteException {
        return socsec;
  }

  public void addBonus(int bonus) throws RemoteException {
        this.bonus += bonus;
  }

  public void ejbCreate(int socsec, int bonus) 
		throws CreateException, RemoteException {
    this.socsec=socsec;
    this.bonus=bonus;
  }

  // Other interface methods

  public void setEntityContext(javax.ejb.EntityContext ctx) 
		throws RemoteException
  {
    this.ctx = ctx;
  }
  public void unsetEntityContext() throws RemoteException {
    ctx = null;
  }

  public void ejbRemove() throws RemoteException, 
			  	 RemoveException { }
  public void ejbActivate() throws RemoteException { }
  public void ejbPassivate() throws RemoteException { }
  public void ejbLoad() throws RemoteException { }
  public void ejbStore() throws RemoteException { }
}

Session Bean Source Code

The session Bean performs a simple calculation. Its source code is similar to the entity Bean source code with the few differences described here.

The home interface does not have a FindByPrimaryKey method because no database access is involved. A session Bean could perform database access, and would then need a FindByPrimaryKey method, but the simple example does not need it.

package com.ejbhome.examples;

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

public interface CalcHome extends EJBHome {
  Calc create() throws CreateException, 
		       RemoteException;
}

The remote interface declares the session Bean's one method.

package com.ejbhome.examples;

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

public interface Calc extends EJBObject {
  int calcBonus(int base, int perf, int company) 
			throws RemoteException;
}

The session Bean implements SessionBean and the developer-defined and interface methods.

package com.ejbhome.examples;

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

public class CalcBean implements SessionBean 
			throws Remote Exception {

  public int bonus;
  protected SessionContext ctx;

  public int calcBonus(int base, int perf, int company) {
    int calc = (base*perf*company);
    this.bonus += calc;
    return this.bonus;
  }

  public void ejbCreate() throws CreateException, 
				 RemoteException {}

  // Other interface methods
  public void setSessionContext(javax.ejb.SessionContext ctx) 
			  throws RemoteException {
    this.ctx = ctx;
  }

  public void ejbRemove() throws RemoteException { }
  public void ejbActivate() throws RemoteException { }
  public void ejbPassivate() throws RemoteException { }
  public void ejbLoad() throws RemoteException { }
  public void ejbStore() throws RemoteException { }
}

Container Classes

The Deployer tool generates these container classes for BonusBean and CalcBean.

BonusBean CalcBean
EJBHomeBonusBean.class EJBHomeBonusBean.java EJBHomeBonusHome.class EJBHomeBonusHome.java EJBHomeBonusHome_Skel.class EJBHomeBonusHome_Skel.java EJBHomeBonusHome_Stub.class EJBHomeBonusHome_Stub.java EJBHomeBonusMetaData.class EJBHomeBonusMetaData.java EJBHomeRemoteBonus.class EJBHomeRemoteBonus.java EJBHomeRemoteBonus_Skel.class EJBHomeRemoteBonus_Skel.java EJBHomeRemoteBonus_Stub.class EJBHomeRemoteBonus_Stub.java EJBHomeCalcBean.class EJBHomeCalcBean.java EJBHomeCalcHome.class EJBHomeCalcHome.java EJBHomeCalcHome_Skel.class EJBHomeCalcHome_Skel.java EJBHomeCalcHome_Stub.class EJBHomeCalcHome_Stub.java EJBHomeCalcMetaData.class EJBHomeCalcMetaData.java EJBHomeRemoteCalc.class EJBHomeRemoteCalc.java EJBHomeRemoteCalc_Skel.class EJBHomeRemoteCalc_Skel.java EJBHomeRemoteCalc_Stub.class EJBHomeRemoteCalc_Stub.java

Conclusion

If you want to develop thin-client multitiered applications for the net, Enterprise JavaBeans is the way to go. You can write business applications with reusable and modular enterprise Beans and leave the system-level programming to the underlying architecture. You will not be alone--the Enterprise JavaBeans architecture has been adopted, supported, and put on the product roadmaps of more than 25 companies.

Here are links to additional information on Enterprise JavaBeans.

Monica Pawlan is a staff writer on the JDC team. She has a background in 2D and 3D graphics, security, database products, and loves to explore emerging technologies.

monica.pawlan@eng.sun.com