MindView Inc.

Thinking in Java, 3rd ed. Revision 2.0


[ Viewing Hints ] [ Book Home Page ] [ Free Newsletter ]
[ Seminars ] [ Seminars on CD ROM ] [ Consulting ]

Previous Next Title Page Index Contents

18: Enterprise JavaBeans

Suppose[95] you need to develop a multi-tiered application to view and update records in a database through a Web interface. You can write a database application using JDBC, a Web interface using JSP/servlets, and a distributed system using CORBA/RMI. But what extra considerations must you make when developing a distributed object system rather than just knowing API’s? Here are the issues: Comment

Performance: The distributed objects you create must perform well, as they could potentially service many clients at a time. You’ll need to use optimization techniques such as caching as well as pooling resources like database connections. You’ll also have to manage the lifecycle of your distributed objects. Comment

Scalability: The distributed objects must also be scalable. Scalability in a distributed application means that the number of instances of your distributed objects can be increased and moved onto additional machines without modifying any code. Comment

Security: A distributed object must often manage the authorization of the clients that access it. Ideally, you can add new users and roles to it without recompilation. Comment

Distributed Transactions: A distributed object should be able to reference distributed transactions transparently. For example, if you are working with two separated databases, you should be able to update them simultaneously within the same transaction and roll them both back if a certain criteria is not met. Comment

Reusability: The ideal distributed object can be effortlessly moved onto another vendors’ application server. It would be nice if you could resell a distributed object component without making special modifications, or buy someone else’s component and use it without having to recompile or rewrite it. Comment

Availability: If one of the machines in the system goes down, clients should automatically fail-over to backup copies of the objects running on other machines. Comment

These considerations, in addition the business problem that you set out to solve, can make for a daunting development project. However, all the issues except for your business problem are redundant—solutions must be reinvented for every distributed business application. Comment

Sun, along with other leading distributed object vendors, realized that sooner or later every development team would be reinventing these particular solutions, so they created the Enterprise JavaBeans specification (EJB). EJB describes a server-side component model that tackles all of the considerations mentioned above using a standard approach that allows developers to create business components called EJBs that are isolated from low-level “plumbing” code and that focus solely on providing business logic. Because EJB’s are defined in a standard way, they can vendor independent. Comment

JavaBeans vs. EJBs

Because of the similarity in names, there is much confusion about the relationship between the JavaBeans component model and the Enterprise JavaBeans specification. While both the JavaBeans and Enterprise JavaBeans specifications share the same objectives in promoting reuse and portability of Java code between development and deployment tools with the use of standard design patterns, the motives behind each specification are geared to solve different problems. Comment

The standards defined in the JavaBeans component model are designed for creating reusable components that are typically used in IDE development tools and are commonly, although not exclusively, visual components. Comment

The Enterprise JavaBeans specification defines a component model for developing server side java code. Because EJBs can potentially run on many different server-side platforms—including mainframes that do not have visual displays—An EJB cannot make use of graphical libraries such as AWT or Swing. Comment

The EJB specification

The Enterprise JavaBeans specification describes a server-side component model. It defines six roles that are used to perform the tasks in development and deployment as well as defining the components of the system. These roles are used in the development, deployment and running of a distributed system. Vendors, administrators and developers play the various roles, to allow the partitioning of technical and domain knowledge. The vendor provides a technically sound framework and the developers create domain-specific components; for example, an “accounting” component. The same party can perform one or many roles. The roles defined in the EJB specification are summarized in the following table:Comment

Role

Responsibility

Enterprise Bean Provider

The developer responsible for creating reusable EJB components. These components are packaged into a special jar file (ejb-jar file).

Application Assembler

Creates and assembles applications from a collection of ejb-jar files. This includes writing applications that utilize the collection of EJBs (e.g., servlets, JSP, Swing etc. etc.).

Deployer

Takes the collection of ejb-jar files from the Assembler and/or Bean Provider and deploys them into a run-time environment: one or more EJB Containers.

EJB Container/Server Provider

Provides a run-time environment and tools that are used to deploy, administer, and run EJB components.

System Administrator

Manages the different components and services so that they are configured and they interact correctly, as well as ensuring that the system is up and running.


EJB components

EJB components are elements of reusable business logic that adhere to strict standards and design patterns as defined in the EJB specification. This allows the components to be portable. It also allows other services—such as security, caching and distributed transactions—to be performed on behalf of the components. An Enterprise Bean Provider is responsible for developing EJB components. Comment

EJB Container & Server

The EJB Container is a run-time environment that contains and runs EJB components and provides a set of standard services to those components. The EJB Container’s responsibilities are tightly defined by the specification to allow for vendor neutrality. The EJB container provides the low-level “plumbing” of EJB, including distributed transactions, security, lifecycle management of beans, caching, threading and session management. The EJB Container Provider is responsible for providing an EJB Container. Comment

An EJB Server is defined as an Application Server that contains and runs one or more EJB Containers. The EJB Server Provider is responsible for providing an EJB Server. You can generally assume that the EJB Container and EJB Server are the same. Comment

Java Naming and Directory Interface (JNDI)

Java Naming and Directory Interface (JNDI) is used in Enterprise JavaBeans as the naming service for EJB Components on the network and other container services such as transactions. JNDI maps very closely to other naming and directory standards such as CORBA CosNaming and can actually be implemeted as a wrapper on top of it. Comment

Java Transaction API/Java Transaction Service (JTA/JTS)

JTA/JTS is used in Enterprise JavaBeans as the transactional API. An Enterprise Bean Provider can use the JTS to create transaction code, although the EJB Container commonly implements transactions in EJB on the EJB components’ behalf. The deployer can define the transactional attributes of an EJB component at deployment time. The EJB Container is responsible for handling the transaction whether it is local or distributed. The JTS specification is the Java mapping to the CORBA OTS (Object Transaction Service). Comment

CORBA and RMI/IIOP

The EJB specification defines interoperability with CORBA through compatibility with CORBA protocols. This is achieved by mapping EJB services such as JTS and JNDI to corresponding CORBA services and the implementation of RMI on top of the CORBA protocol IIOP. Comment

Use of CORBA and RMI/IIOP in Enterprise JavaBeans is implemented in the EJB Container and is the responsibility of the EJB Container provider. Use of CORBA and RMI/IIOP in the EJB Container is hidden from the EJB Component itself. This means that the Enterprise Bean Provider can write their EJB Component and deploy it into any EJB Container without any regard of which communication protocol is being used. Comment

The pieces of an EJB component

An EJB consists of a number of pieces, including the Bean itself, the implementation of some interfaces, and an information file. Everything is packaged together into a special jar file. Comment

Enterprise Bean

The Enterprise Bean is a Java class that the Enterprise Bean Provider develops. It implements an Enterprise Bean interface and provides the implementation of the business methods that the component is to perform. The class does not implement any authorization, authentication, multithreading, or transactional code. Comment

Home interface

Every Enterprise Bean that is created must have an associated Home interface. The Home interface is used as a factory for your EJB. Clients use the Home interface to find an instance of your EJB or create a new instance of your EJB. Comment

Remote interface

The Remote interface is a Java Interface that reflects the methods of your Enterprise Bean that you wish to expose to the outside world. The Remote interface plays a similar role to a CORBA IDL interface. Comment

Deployment descriptor

The deployment descriptor is an XML file that contains information about your EJB. Using XML allows the deployer to easily change attributes about your EJB. The configurable attributes defined in the deployment descriptor include:

EJB-Jar file

The EJB-Jar file is a normal java jar file that contains your EJB, Home and Remote interfaces, as well as the deployment descriptor. Comment

EJB operation

Once you have an EJB-Jar file containing the Bean, the Home and Remote interfaces, and the deployment descriptor, you can fit all of the pieces together and in the process understand why the Home and Remote interfaces are needed and how the EJB Container uses them. Comment

The EJB Container implements the Home and Remote interfaces that are in the EJB-Jar file. As mentioned earlier, the Home interface provides methods to create and find your EJB. This means that the EJB Container is responsible for the lifecycle management of your EJB. This level of indirection allows for optimizations to occur. For example, 5 clients might simultaneously request the creation of an EJB through a Home Interface, and the EJB Container would respond by creating only one EJB and sharing it between all 5 clients. This is achieved through the Remote Interface, which is also implemented by the EJB Container. The implemented Remote object plays the role of a proxy object to the EJB. Comment

All calls to the EJB are ‘proxied’ through the EJB Container via the Home and Remote interfaces. This indirection is the reason why the EJB container can control security and transactional behavior. Comment

Types of EJBs

The Enterprise JavaBeans specification defines different types of EJBs that have different characteristics and behaviors. Two categories of EJBs have been defined in the specification: Session Beans and Entity Beans, and each categoriy has variations. Comment

Session Beans

Session Beans are used to represent Use-Cases or Workflow on behalf of a client. They represent operations on persistent data, but not the persistent data itself. There are two types of Session Beans, Stateless and Stateful. All Session Beans must implement the javax.ejb.SessionBean interface. The EJB Container governs the life of a Session Bean. Comment

Stateless Session Beans are the simplest type of EJB component to implement. They do not maintain any conversational state with clients between method invocations so they are easily reusable on the server side and because they can be cached, they scale well on demand. When using Stateless Session Beans, all state must be stored outside of the EJB. Comment

Stateful Session Beans maintain state between invocations. They have a one-to-one logical mapping to a client and can maintain state within themselves. The EJB Container is responsible for pooling and caching of Stateful Session Beans, which is achieved through Passivation and Activation. If the EJB Container crashes, data for all Stateful Session Beans could be lost. Some high-end EJB Containers provide recovery for Stateful Session Beans. Comment

Entity Beans

Entity Beans are components that represent persistent data and behavior of this data. Entity Beans can be shared among multiple clients, the same way that data in a database can be shared. The EJB Container is responsible for caching Entity Beans and for maintaining the integrity of the Entity Beans. The life of an Entity Bean outlives the EJB Container, so if an EJB Container crashes, the Entity Bean is still expected to be available when the EJB Container again becomes available. Comment

There are two types of Entity Beans: those with Container Managed persistence and those with Bean-Managed persistence. Comment

Container Managed Persistence (CMP). A CMP Entity Bean has its persistence implemented on its behalf by the EJB Container. Through attributes specified in the deployment descriptor, the EJB Container will map the Entity Bean’s attributes to some persistent store (usually—but not always—a database). CMP reduces the development time for the EJB, as well as dramatically reducing the amount of code required. Comment

Bean Managed Persistence (BMP). A BMP Entity Bean has its persistence implemented by the Enterprise Bean Provider. The Enterprise Bean Provider is responsible for implementing the logic required to create a new EJB, update some attributes of the EJBS, delete an EJB and find an EJB from persistent store. This usually involves writing JDBC code to interact with a database or other persistent store. With BMP, the developer is in full control of how the Entity Bean persistence is managed. Comment

BMP also gives flexibility where a CMP implementation may not be available. For example, if you wanted to create an EJB that wrapped some code on an existing mainframe system, you could write your persistence using CORBA. Comment

Developing an EJB

As an example, the “Perfect Time” example from the previous RMI section will be implemented as an EJB component. The example will be a simple Stateless Session Bean. Comment

As mentioned earlier, EJB components consist of at least one class (the EJB) and two interfaces: the Remote and Home interfaces. When you create a Remote interface for an EJB , you must follow these guidelines: Comment

  1. The remote interface must be public. Comment
  2. The remote interface must extend the interface javax.ejb.EJBObject. Comment
  3. Each method in the remote interface must declare java.rmi.RemoteException in its throws clause in addition to any application-specific exceptions. Comment
  4. Any object passed as an argument or return value (either directly or embedded within a local object) must be a valid RMI-IIOP data type (this includes other EJB objects).Comment

Here is the simple remote interface for the PerfectTime EJB:

//: c15:ejb:PerfectTime.java
//# You must install the J2EE Java Enterprise 
//# Edition from java.sun.com and add j2ee.jar
//# to your CLASSPATH in order to compile
//# this file. See details at java.sun.com.
// Remote Interface of PerfectTimeBean
// {Depends: j2ee.jar}
import java.rmi.*;
import javax.ejb.*;

public interface PerfectTime extends EJBObject {
  public long getPerfectTime() 
    throws RemoteException;
} ///:~


The Home interface is the factory where the component will be created. It can define create methods, to create instances of EJBs, or finder methods, which locate existing EJBs and are used for Entity Beans only. When you create a Home interface for an EJB , you must follow these guidelines:

  1. The Home interface must be public. Comment
  2. The Home interface must extend the interface javax.ejb.EJBHome. Comment
  3. Each create method in the Home interface must declare java.rmi.RemoteException in its throws clause as well as a javax.ejb.CreateException. Comment
  4. The return value of a create method must be a Remote Interface. Comment
  5. The return value of a finder method (Entity Beans only) must be a Remote Interface or java.util.Enumeration or java.util.Collection. Comment
  6. Any object passed as an argument (either directly or embedded within a local object) must be a valid RMI-IIOP data type (this includes other EJB objects) Comment

The standard naming convention for Home interfaces is to take the Remote interface name and append “Home” to the end. Here is the Home interface for the PerfectTime EJB: Comment

//: c15:ejb:PerfectTimeHome.java
// Home Interface of PerfectTimeBean.
// {Depends: j2ee.jar}
import java.rmi.*;
import javax.ejb.*;

public interface PerfectTimeHome extends EJBHome {
  public PerfectTime create() 
    throws CreateException, RemoteException;
} ///:~


You can now implement the business logic. When you create your EJB implementation class, you must follow these guidelines, (note that you should consult the EJB specification for a complete list of guidelines when developing Enterprise JavaBeans): Comment

  1. The class must be public. Comment
  2. The class must implement an EJB interface (either javax.ejb.SessionBean or javax.ejb.EntityBean). Comment
  3. The class should define methods that map directly to the methods in the Remote interface. Note that the class does not implement the Remote interface; it mirrors the methods in the Remote interface but does not throw java.rmi.RemoteException. Comment
  4. Define one or more ejbCreate( ) methods to initialize your EJB. Comment
  5. The return value and arguments of all methods must be valid RMI-IIOP data types. Comment
//: c15:ejb:PerfectTimeBean.java
// Simple Stateless Session Bean 
// that returns current system time.
// {Depends: j2ee.jar}
import java.rmi.*;
import javax.ejb.*;

public class PerfectTimeBean 
  implements SessionBean {
  private SessionContext sessionContext;
  //return current time
  public long getPerfectTime() { 
     return System.currentTimeMillis();
  }
  // EJB methods
  public void ejbCreate() 
  throws CreateException {}
  public void ejbRemove() {}
  public void ejbActivate() {}
  public void ejbPassivate() {}
  public void 
  setSessionContext(SessionContext ctx) {
    sessionContext = ctx;
  }
}///:~


Because this is a simple example, the EJB methods (ejbCreate( ), ejbRemove( ), ejbActivate( ), ejbPassivate( ) ) are all empty. These methods are invoked by the EJB Container and are used to control the state of the component. The setSessionContext( ) method passes a javax.ejb.SessionContext object which contains information about the component’s context, such as the current transaction and security information. Comment

After we have created the Enterprise JavaBean, we then need to create a deployment descriptor. The deployment descriptor is an XML file that describes the EJB component. The deployment descriptor should be stored in a file called ejb-jar.xml. Comment

//:! c15:ejb:ejb-jar.xml
<?xml version="1.0" encoding="Cp1252"?>
<!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>
  <description>Example for Chapter 15</description>
  <display-name></display-name>
  <small-icon></small-icon>
  <large-icon></large-icon>
  <enterprise-beans>
    <session>
      <ejb-name>PerfectTime</ejb-name>
      <home>PerfectTimeHome</home>
      <remote>PerfectTime</remote>
      <ejb-class>PerfectTimeBean</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
    </session>
  </enterprise-beans>
  <ejb-client-jar></ejb-client-jar>
</ejb-jar>
///:~


You can see the Component, the Remote interface and the Home interface defined inside the <session> tag of this deployment descriptor. Deployment descriptors may be automatically generated using EJB development tools. Comment

Along with the standard ejb-jar.xml deployment descriptor, the EJB specification states that any vendor specific tags should be stored in a separate file. This is to achieve high portability between components and different brands of EJB containers. Comment

The files must be archived inside a standard Java Archive (JAR) file. The deployment descriptors should be placed inside the /META-INF sub-directory of the Jar file. Comment

Once the EJB component is defined in the deployment descriptor, the deployer should then deploy the EJB component into the EJB Container. At the time of this writing, the deployment process was quite “GUI intensive” and specific to each individual EJB Container, so this overview does not document that process. Every EJB Container, however will have a documented process for deploying an EJB. Comment

Because an EJB component is a distributed object, the deployment process should also create some client stubs for calling the EJB component. These classes should be placed on the classpath of the client application. Because EJB components can be implemented on top of RMI-IIOP (CORBA) or RMI-JRMP, the stubs generated could vary between EJB Containers; nevertheless they are generated classes. Comment

When a client program wishes to invoke an EJB, it must look up the EJB component inside JNDI and obtain a reference to the home interface of the EJB component. The Home interface is used to create an instance of the EJB. Comment

In this example the client program is a simple Java program, but you should remember that it could just as easily be a servlet, a JSP or even a CORBA or RMI distributed object.

//: c15:ejb:PerfectTimeClient.java
// Client program for PerfectTimeBean
// {Depends: j2ee.jar}

public class PerfectTimeClient {
public static void main(String[] args)
throws Exception {
  // Get a JNDI context using
  // the JNDI Naming service:
  javax.naming.Context context =
    new javax.naming.InitialContext();
  // Look up the home interface in the
  // JNDI Naming service:
  Object ref = context.lookup("perfectTime");
  // Cast the remote object to the home interface:
  PerfectTimeHome home = (PerfectTimeHome)
    javax.rmi.PortableRemoteObject.narrow(
      ref, PerfectTimeHome.class);
  // Create a remote object from the home interface:
  PerfectTime pt = home.create();
  // Invoke  getPerfectTime()
  System.out.println(
    "Perfect Time EJB invoked, time is: " +
    pt.getPerfectTime() );
  }
} ///:~


The sequence of the example is explained in the comments. Note the use of the narrow( ) method to perform a kind of casting of the object before a Java cast is performed. This is very similar to what happens in CORBA. Also note that the Home object becomes a factory for PerfectTime objects. Comment

EJB summary

The Enterprise JavaBeans specification is a dramatic step forward in the standardization and simplification of distributed object computing. It is a major piece of the Java 2 Enterprise Edition (J2EE) platform and is receiving much support from the distributed object community. Many tools are currently available or will be available in the near future to help accelerate the development of EJB components. Comment

This overview was only a brief tour of EJBs. For more information about the EJB specification you should see the official Enterprise JavaBeans home page at java.sun.com/products/ejb/, where you can download the latest specification and the J2EE reference implementation. These can be used to develop and deploy your own EJB components. Comment



[95] This section was contributed by Robert Castaneda, with help from Dave Bartlett.


Previous Next Title Page Index Contents