Enterprise Java Beans  from Eckel and Object People Material.

Could you imagine trying to develop a large-scale application using CORBA and/or RMI? Your manager has asked you to develop a multi-tiered application to view and update records in a database through a Web interface. You sit back and think of what that really means. Sure, 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 based system rather than just knowing API's? Here are the issues:

Performance: The new distributed objects that you are creating are going to have to perform, as they potentially could service many clients at a time. So you'll want to think of optimization techniques such as caching, pooling of resources (e.g., JDBC database connections). You'll also have to manage the lifecycle of your distributed object.

Scalability: The distributed objects must also be scalable. Scalable in a distributed application sense means that the number of instances of your distributed object can be increased and moved over to a different machine without the modification of any code. Take for example a system that you develop internally as a small lookup of clients inside your organization from a database. The application works well when you use it, but your manager has seen it and has said "Robert, that is an excellent system, get it on our public Web-site now!!!"-Will my distributed object be able to handle the load of a potentially limitless demand?

Security: Does my distributed object manage the authorization of the clients that accesses it? Can I add new users and roles to it without recompilation?

Distributed Transactions: Can my distributed object reference distributed-transactions transparently? Can I update my Oracle and Sybase databases simultaneously within the same transaction and roll them both back if a certain criteria is not met?
 

Reusability: Have I created my distributed object so that I can move it into another vendors' application server? Can I resell my distributed object (component) to somebody else? Can I buy somebody else's component and use it without having to recompile and 'hack it into shape'?

Availability: If one of the machines in my system was to go down, are my clients able to automatically fail-over to back up copies of my objects running on other machines?

As you can see from the above, the considerations that a developer must make when developing a distributed system and we haven't even mentioned solving the problem that we were originally trying to solve!

So you now have your list of extra problems that you must solve. So how do you go about doing it? Surely somebody must have done this before? Could I use some well-known design patterns to help me solve these problems? Then an idea flashes in your head... "I could create a framework that handles all of these issues and write my components on top of the framework!".... This is where Enterprise JavaBeans comes into the picture.

Sun, along with other leading distributed object vendors realized that sooner or later every development team would be reinventing the wheel. So they created the Enterprise JavaBeans specification (EJB). EJB is a specification for a server-side component model that tackles all of the considerations mentioned above using a defined, standard approach that allows developers to create components-which are actually called Enterprise JavaBeans (EJB's)-that are isolated from low-level 'plumbing' code and focus solely on providing business logic. Because EJB's are defined as a standard they can be used without being vendor dependent.

What’s defined in the EJB specification?
The Enterprise JavaBeans specification, currently at version 1.1 - public release 2 - defines a server side component model. It defines 6 roles that are used to perform the tasks in development and deployment as well as defining the components of the system.

Roles
The EJB specification defines roles that are used during in the development, deployment and running of a distributed system. Vendors, administrators and developers play the various roles. They allow the partitioning of technical and domain knowledge. This allows the vendor to provide a technically sound framework and the developers to create domain specific components e.g., an Accounting component. The same party can perform one or many roles. The roles defined in the EJB specification have been summarized in the following table:

Role / Responsibility

Enterprise Bean Provider

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

Application Assembler

 Create and assemble applications from a collection of ejb-jar files. This includes writing applications that utilize the collection of EJB’s (e.g., Servlets, JSP, Swing etc. etc.)

Deployer

 The Deployer’s role of the to take the collection of ejb-jar files from the Assembler and/or Bean Provider and deploy them into a run-time environment - one or many EJB Container(s).

EJB Container/Server Provider

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

System Administrator

 Over see the most important goal of the entire system - That it is up and running. Management of a distributed application can consist of many different components and services all configured and interacting together correctly.

Components of EJB

EJB components are reusable business logic. EJB components adhere to strict standards and design patterns as defined in the EJB specification. This allows the components to be portable and also allow other services—such as security, caching and distributed transactions - to be performed on the components’ behalf. An Enterprise Bean Provider is responsible for developing EJB components. The internals of an EJB component are covered in - “What makes up an EJB component?”

EJB Container
The EJB Container is a run-time environment that contains -or runs—EJB components and provides a set of standard services to the components. The EJB Containers 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, life cycle management of beans, caching, threading and session management. The EJB Container Provider is responsible for providing an EJB Container.

EJB Server
An EJB Server is defined as an Application Server that contains and runs 1 or more EJB Containers. that both the Container and Server are the same vendor. The EJB Server Provider is responsible for providing an EJB Server. The specification suggests and you can assume for this introduction, that the EJB Container and EJB Server are the same.

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.

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 transactional 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)

CORBA and RMI/IIOP
The EJB specification defines interoperablility with CORBA. The 1.1 specification quotes “The Enterprise JavaBeans architecture will be compatible with the CORBA protocols.” CORBA interoperability is achieved through the mapping of EJB services such as JTS and JNDI to corresponding CORBA services and the implementation of RMI on top of the CORBA protocol IIOP.

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.

The components and available services of EJB:

What makes up an EJB component?

Enterprise Bean
The Enterprise Bean is a Java class that the Enterprise Bean Provider develops. It implements an EnterpriseBean interface (more detail in a later section) and provides the implementation of the business methods that the component is to perform. The class does not implement any authorization/authentication code, multithreading, transactional code.

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.

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.

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:

The Home and Remote interface names that are required by your EJB
The name to publish into JNDI for your EJB’s Home interface
Transactional attributes for each method of your EJB
Access Control Lists for authentication

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.

How does EJB work?
Now that we have our EJB-Jar file containing our Bean, Home and Remote interfaces and Deployment Descriptor, Let’s take a look at how all of these pieces fit together and why Home and Remote interfaces are needed and how the EJB Container uses them.

Who implements the Home and Remote Interfaces?

The EJB Container implements the Home and Remote interfaces that are in our EJB-Jar file. Because the EJB Container implements the Home interface that - as mentioned earlier - 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 simultaneously request to create an EJB through a Home Interface, the EJB Container could create only one and share that EJB between all 5 clients. This is achieved through the Remote Interface, which is again implemented by the EJB Container. The implemented Remote object plays the role of a proxy object to the EJB.

The following diagram show the level of indirection achieved by this approach and that all calls to the EJB are ‘proxied’ through the EJB Container via the Home and Remote interfaces. This level of indirection is also the reason why the EJB Container can control security and transactional behavior.

Types of EJB’s

There should be one question in your head from the previous section, “Surely sharing the same EJB between clients can improve performance, but what If I want to maintain state on my server?”

The Enterprise JavaBeans specification defines different types of EJB’s that have different characteristics and exhibit different behavior. Two categories of EJB’s have been defined in the specification. Session Beans and Entity Beans, and each of these categories has variations. A hierarchy of the various types of EJB components is shown in the following figure.

Session Beans

Session Beans are used to represent Use-Cases or Workflow on behalf of a client. They represent operations on persistent data, not 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. 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.

Stateless Session Beans
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.

Stateful Session Beans
Stateful Session Beans - as you could probably guess - maintain state between invocations. They have a 1 to 1 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.

Entity Beans

Entity Beans are components that represent persistent data and behavior of this data. Entity Beans can be shared amongst multiple clients, the same as data in a database. 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 expected to still be available when the EJB Container becomes available.

There are two types of Entity Beans, those that have Bean-Managed persistence and Container Managed persistence.

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 time to develop and dramatically reduces the amount of code required for the EJB.

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.

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

How do I put the ‘E’ in my existing JavaBeans?

There is much confusion about the relationship between the JavaBeans component model and the Enterprise JavaBeans specification. Whilst 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.

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.

The Enterprise JavaBeans specification defines a component model for developing server side java code. Because EJB’s can potentially run on many different server-side platforms -including mainframes that do not have visual displays - An EJB cannot make use of the java.awt package.

Developing an Enterprise Java Bean

We will now implement the “Perfect Time” example from the previous RMI section as an Enterprise JavaBean component. The example will be a simple Stateless Session Bean. Enterprise JavaBean components will consist of at least one class and two interfaces.

The first interface defined is the Remote Interface to our Enterprise JavaBean component. When you create a Remote interface for an EJB , you must follow these guidelines:

1. The remote interface must be public.
2. The remote interface must extend the interface javax.ejb.EJBObject.
3. Each method in the remote interface must declare java.rmi.RemoteException in its throws clause in addition to any application-specific exceptions.
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)
Here is the simple remote interface for our 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
import java.rmi.*;
import javax.ejb.*;

public interface PerfectTime extends EJBObject {
  public long getPerfectTime()
    throws RemoteException;
} ///:~
The second interface defined is the Home Interface to our Enterprise JavaBean component. The Home interface is the factory where our component will be created. The Home interface can define create or finder methods. Create methods create instances of EJB’s, finder methods locate existing EJB’s and are used for Entity Beans only. When you create a Home interface for an EJB , you must follow these guidelines:
 

The Home interface must be public.
The Home interface must extend the interface javax.ejb.EJBHome.
Each method in the Home interface must declare java.rmi.RemoteException in its throws clause as well as a javax.ejb.CreateException
The return value of a create method must be a Remote Interface
The return value of a finder method (Entity Beans only) must be a Remote Interface or java.util.Enumeration or java.util.Collection
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)
The standard naming convention for Home interfaces is to take the Remote interface name and append “Home” to the end. Following is the Home interface for our PerfectTime EJB:
 

//: c15:ejb:PerfectTimeHome.java
// Home Interface of PerfectTimeBean.
import java.rmi.*;
import javax.ejb.*;

public interface PerfectTimeHome extends EJBHome {
  public PerfectTime create()
    throws CreateException, RemoteException;
} ///:~
Now that we have defined the interfaces of our component, we can now implement the business logic behind it. 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):
 

The class must be public.
The class must implement an EJB interface (either javax.ejb.SessionBean or javax.ejb.EntityBean).
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.
Define one or more ejbCreate( ) methods to initialize your EJB.
The return value and arguments of all methods must be valid RMI-IIOP data types.

//: c15:ejb:PerfectTimeBean.java
// Simple Stateless Session Bean
// that returns current system time.

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;
  }
}///:~
Notice that 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 our component. As this is a simple example, we can leave these empty. The setSessionContext( ) method passes a javax.ejb.SessionContext object which contains information about context that the component is in, such as the current transaction and security information.

After we have created our Enterprise Java Bean, we then need to create a Deployment Descriptor. In EJB 1.1, 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.
 

<?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>
Inside the <session> tag of our deployment descriptor we can see that our Component, the Remote interface and Home interfaces are begin defined. Deployment Descriptors can easily be automatically generated inside tools such as JBuilder.
 

Along with the standard ejb-jar.xml deployment descriptor the EJB 1.1 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 EJB containers.
 

Now that we have created our component, and defined it’s composition in the Deployment Descriptor we then need to archive the files inside a standard Java Archive (JAR) file. The Deployment Descriptors should be placed inside the /META-INF sub-directory of the Jar file.
 

Once we have defined our EJB component in the Deployment Descriptor, the Deployer should then deploy the EJB component into the EJB Container. At the time of writing, this process was quite "gui intensive" and specific to each individual EJB Container, so we decided not to document the entire deployment process in this overview. Every EJB Container, however will have a documented process for deploying an EJB.
 

Because an EJB component is a distributed object, the deployment process should also create some client stubs for calling the EJB component. These classes whould 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.
 

When a client program wishes to invoke an EJB, it must lookup the EJB component inside JNDI and obtain a reference to the Home interface of the EJB component. The Home Interface can then be invoked to create an instance of the EJB, which can then be invoked.
 

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 even a CORBA or RMI distributed object.
 

The PerfectTimeClient code is as follows.
 

//: c15:ejb:PerfectTimeClient.java
// Client program for PerfectTimeBean

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() );
  }
} ///:~
 
 

In Summary

The Enterprise JavaBeans specification - although intially seems very daunting - is a dramatic step forward in the standardization and simplification or distributed object computing. It is a major piece of the Java 2, Enterprise Edition Platform and is receiving much support from the Distributed Object community. Many tools are currently available or will be in the near future to help accelerate the development of EJB components.

This overview was aimed at giving you a brief tour as to what EJB is all about. For more information about the Enterprise JavaBeans specification you should see the Official Enterprise JavaBeans Home Page at http://java.sun.com/products/ejb/. Here you can download the latest specification as well as the Java 2, Enterprise Edition Reference Implementation, which you can use to develop and deploy your own EJB components.