HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

Developing and maintaining distributed business applications is hard. As if writing business logic weren't hard enough, enterprise application developers have also been saddled traditionally with the daunting task of implementing transaction management, persistent state management, thread safety, resource pooling, security, distribution and life cycle/location of business objects. This makes enterprise application development more time-consuming and costly, and requires a broad range of expertise from the development team.

Once an enterprise application has been developed, using its code across other business applications becomes difficult because: (1) business logic is mixed with code to manage transactions, persistence, security and resources; and (2) other applications may employ different programming models. Ideally, one would like to reuse business logic as much as possible to ensure consistency of business rules across a company's applications.

Likewise, it's difficult to reuse code across platforms, servers and backing stores (e.g., databases) when the business application contains low-level API calls that are specific to a particular platform or product. Portability across platforms is particularly desirable when you want to support client access from customer systems. Portability across server and database products allows an application to be migrated to higher-end systems as the business grows and its needs change.

Enterprise JavaBeans is a new specification from Sun Microsystems that aims to simplify the development, maintenance and code reuse of multitier enterprise business applications. Enterprise Java-Beans (EJB) is, foremost, a component model; that is, it facilitates reuse of software building blocks (components). A component model specifies the way a component interacts with its environment and other components, and offers programmers guidelines for building components so they can be dynamically composed with other components.

Enterprise JavaBeans is an object-oriented component model that focuses on the development and packaging of multitier enterprise Java applications. Like Java-Beans components, Enterprise JavaBeans are objects that can be used without source code because they can be customized through their external properties. Unlike JavaBeans components, Enterprise Java-Beans are always accessed remotely, as part of a distributed, multitier application. Such an application is typically characterized by a thin client (one containing only presentation logic) accessing remote business objects. The business logic and data access logic reside on one or more servers. The benefits of multitier applications include scalability, performance, reliability and flexibility; such applications are well suited to high-volume business transactions and Web-based business applications. Because the client contains only presentation logic, multitier applications can support a wide variety of client devices.

Goals of the Enterprise JavaBeans Specification
A major goal of the EJB specification - to simplify the programming model for distributed enterprise applications - is accomplished in four ways:

  1. EJB is based on the Java programming language.
  2. It's also based on the JavaBeans component model, an easy-to-use programming model that relies on simple programming and naming conventions for creating reusable, portable, customizable Java components. Enterprise JavaBeans are special, nonvisual JavaBeans that run on a server.
  3. EJB includes a set of high-level APIs for transaction, security and persistence management; these APIs must be supported by an EJB-compliant server product.
  4. The EJB programming model allows the programmer to focus on the business logic rather than coding thread safety, concurrency, resource pooling, security checking and transaction management. The EJB-compliant server product is required to perform these services automatically on behalf of the Enterprise JavaBean.
A second major goal is to enable reuse. EJB inherently enables reuse across applications because it's based on an object-oriented programming language (Java) and a component model (JavaBeans), and it inherits the cross-platform portability of Java. EJB goes further, however, enabling reuse across servers, transaction managers, database products and application-assembly tools. It does this by standardizing - and requiring servers to automate - services like transactions, security and persistence. Each Enterprise JavaBean is required to implement certain interfaces so as to allow the server to manage it, and the server is required to give the Enterprise JavaBean control at certain well-defined execution points. This programming model allows the programmer to isolate the business logic, yielding greater portability.

A third major goal of the EJB specification is to support heavy-duty business applications - those that are distributed, scalable, transactional, multiuser, secure, persistent, flexible, high-performance and CORBA-interoperable. CORBA is an industry-standard architecture published by the OMG consortium for distributed, cross-language object servers. Because EJB is CORBA-interoperable, Enterprise JavaBeans can be hosted in CORBA servers and accessed by non-Java clients or by ActiveX clients using a COM-CORBA bridge. CORBA interoperability will be achieved by enhancing Java RMI to communicate using a CORBA-compliant wire protocol called IIOP. This enhanced implementation of RMI is typically called "RMI over IIOP."

Enterprise JavaBeans Architecture
Figure 1 illustrates the processes (shown as boxes) and objects (shown as ovals) that exist at runtime in an Enterprise JavaBeans application. The client application process contains only presentation logic and stubs to remote business logic objects. As in Java RMI, the client code interacts with the stubs as if they were local objects, and the stubs present the same interface to the client as the remote business objects.

Figure 1
Figure 1:

The EJB server process hosts one or more EJB containers. An EJB container provides the application context for Enterprise JavaBeans, management and control services, and manages security, distributed transactions and state persistence for them. It is expected that each EJB-compliant server product will provide at least one EJB container.

Each container hosts one or more EJBHome objects that manage a single class of Enterprise JavaBeans. An EJBHome provides a remote interface that client applications can use to create new (or find existing) Enterprise JavaBean instances of the class that it manages. An EJBHome also provides a naming context for the Enterprise Java-Beans that it manages. This means that client applications can use the Java Naming and Directory Interface (JNDI) to look up the EJBHome in the namespace - without a priori knowledge of where in the network its server resides - to obtain a stub to the EJBHome.

For each Enterprise JavaBean instance residing in the server, there is a corresponding object called an EJBObject, which represents the client view of the Enterprise JavaBean. It provides a remote interface consisting only of the Enterprise JavaBean's business methods, which a client application invokes via a stub to the EJBObject. The EJBObject's role is to intercept all client requests (even those coming from other EJBs residing in the same server) so that qualities of service for transactions, security and so forth can be maintained transparently to both the EJB and its client. When the EJBObject receives a business method invocation, it delegates to the business logic implemented in the Enterprise JavaBean.

Of all the runtime objects shown in Figure 1, only the Enterprise JavaBean is implemented by the developer. The remaining object implementations are generated by the server/container product's EJB deployment tools. This gives the developer a simple programming model, one that allows the business logic to be isolated and hence portable across EJB server products.

Session Beans vs Entity Beans
The Enterprise JavaBeans specification gives the developer flexibility by supporting multiple types of components. One distinction made in the specification is between session beans - transient, nonrecoverable, unshared components that represent operations to be performed on behalf of a client - and entity beans - persistent, recoverable, shared components that typically represent data backed by a database or other backing store, identified by a unique primary key.

A session bean exists (logically) for the duration of a single client/server session dedicated to one client. Although these beans can access and update a persistent store, they typically do not, and the container provides no support for session bean persistence other than notifying the bean of transactional boundaries. Session beans are typically either stateless service provider components or components that maintain conversational states with a particular client. The container is required to manage the conversational state of a session bean, saving it if the bean is passivated by the server and restoring it when the bean is reactivated.

Another distinction made in the specification is between container-managed and bean-managed entity beans. The distinction refers to how the persistent state of the EJB is managed. The former implementation contains no code to open, access or update a backing store; the container is responsible for managing the persistent store on behalf of the bean. This would include, for instance, reading a row in a relational database in order to initialize the bean's container-managed fields and updating the database before passivating the bean. When deploying a container-managed entity bean to run in a particular server/container product, one would use the deployment tools provided by the product to describe the mapping between the persistent store (e.g., a relational database table's columns) and the bean's container-managed public fields. By contrast, a bean-managed entity bean performs all of its own persistent data management. This might be useful when the bean accesses legacy data in a backing store not supported by the server/container product on which the bean is deployed.

In addition to persistent storage management, EJB-compliant server/container products are also responsible for providing services such as life-cycle management, concurrency, distribution, exception handling, transactions and security.

Writing an Enterprise JavaBean
To write an Enterprise JavaBean, the developer must write two Java interfaces and one Java class. The two interfaces provide the client view of the Enterprise Java-Bean's EJBObject and EJBHome; the class provides the business logic (the bean implementation). Listing 1 shows two interfaces one might write for an entity bean representing a hotel room record in a database. The bean's remote interface, HotelRoom, must extend the EJBObject interface from the java.ejb package (a package introduced by the EJB specification). The bean's home interface, HotelRoomHome, must extend the javax.ejb.EJBHome interface. Both javax.ejb.EJBObject and javax.ejb.EJBHome extend the java.rmi.Remote interface, meaning that these interfaces can be invoked remotely via a stub. Because they are Remote interfaces, every method must include the java.rmi.RemoteException in its throws clause, as well as other application-specific and EJB-specific exceptions.

The bean's remote interface (extending javax.ejb.EJBObject) includes all - and only - the business methods that the bean exposes to client applications. For example, a HotelRoom EJB might provide a method to reserve the hotel room it represents for a specified number of days. The bean's home interface (extending javax.ejb.EJBHome) provides methods of two kinds: creation methods (which must be named "create") and finder methods (which must begin with "find"). Finder methods are allowed only on the home interfaces of entity beans, not session beans. The creation and finder methods can take arbitrary parameters, except that one finder method (named findByPrimaryKey) is required to take an instance of the bean's primary key class as input. The creation and finder methods must return an instance of the bean's remote interface (or finder methods can return a collection of instances).

Listing 2 shows the bean implementation that one might write, corresponding to the interfaces shown in Listing 1. The bean class must implement either the javax.ejb.EntityBean or the javax.ejb.SessionBean interface. This example shows an entity bean; the details of writing a session bean vary slightly.

The bean implementation contains four kinds of items. First, the bean implements all the business methods from the corresponding EJBObject interface. Second, the bean implements methods from the EntityBean (or SessionBean) interface. These methods exist primarily to allow the bean to get callbacks at certain execution points; the bean developer is not required to do anything in these methods. The exception is that when developing a bean-managed entity bean, the bean developer must perform the appropriate backing-store synchronization in the ejbLoad, ejbStore and ejbRemove methods.

Third, for each create method in the bean's home interface, the bean must implement a corresponding ejbCreate and ejbPostCreate method, and its parameters should match the create method. For a container-managed entity bean, the ejbCreate method returns void, and is responsible for initializing the bean instance's container-managed public fields based on the input parameters. (The container is responsible for later updating the backing store based on the instance's field values.) For a bean-managed entity bean, the ejbCreate method returns a primary key value computed from the input parameters, and is responsible for initializing the bean's fields and updating the backing store. The ejbPostCreate method for both kinds of entity beans returns void; it allows the bean developer to perform postcreation computation, but often it would do nothing.

For bean-managed entity beans only, for each finder method in the bean's home interface, the bean must implement a corresponding ejbFind method, with parameters that match the home's finder method. The ejbFind method must compute and return a primary key value based on the input parameters.

Fourth, a container-managed entity bean exposes its container-managed data as public fields. The container is responsible for reading and writing these fields as it updates and accesses the backing store.

Notice that the EJB implementation need not contain any code to access a backing store, manage transactions, impose security constraints or ensure thread safety. The services provided by the server/container allow the developer to focus almost entirely on the application's business logic.

The Enterprise JavaBean developer finally packages the two interfaces and one class that constitutes the EJB into a special kind of zip file called an ejb-jar. The ejb-jar also contains other classes on which the bean depends: a manifest file that describes the ejb-jar's contents and a serialized deployment descriptor object. The deployment descriptor indicates what runtime services the bean requires from the server/container and how the container should manage the bean, particularly with respect to life cycle, persistence, transactions and security. The environment properties embedded in the deployment descriptor allow an application developer to customize the bean for a specific use. For instance, environment properties might indicate the name of a database to be used by a bean-managed entity bean, or indicate the JNDI names of other EJBs that it uses.

Writing an Enterprise JavaBeans Client Application
Listing 3 shows pseudocode that illustrates how one would write client code to remotely access an Enterprise JavaBean and its home. (The requisite exception-handling code is omitted for brevity.) The client application programming model illustrated would also apply when one Enterprise JavaBean is using another Enterprise JavaBean.

First, the client application must locate the bean's home object, using JNDI. To do so, the client application must have the bean's JNDI name, which it could obtain dynamically from a property setting. The client initializes JNDI by creating a javax.naming.InitialContext object, performs a JNDI lookup, passing the bean's JNDI name (e.g., "applications/hotel/rooms"), then narrows the return value to an instance of the bean's home interface. (Think of a narrow operation as a typecast that works on remote objects.) The result is an RMI stub to the bean's home object, residing in a server somewhere on the network.

Second, the client application uses the bean's home to create a new bean instance or find an existing bean instance in the server where the home object resides. For entity beans, creation results in adding new data to the persistent store; finding simply activates (if necessary) a new instance of the bean class to represent data that already exists in the persistent store. Hence, client applications typically use a home's create methods when working with session beans and a home's finder methods when working with entity beans. The result of invoking a creation or finder method on the home stub is another RMI stub, an RMI stub to the bean's EJBObject.

Third, the client application invokes business methods on the bean's EJBObject via the stub returned by the home. This is done exactly as if the bean implementation were being used as a local object, except that the client application must always be prepared to catch a java.rmi.RemoteException.

When the client application finishes using the bean, it will sometimes want to remove it. For an entity bean, removing the bean results in removing data from the persistent store.

As this is typically not desired, the remove method is usually invoked only when using session beans. When a client application is finished using an entity bean whose persistent data should remain in the backing store, the client application need not perform any action to release the bean other than allowing the local stub object to be garbage-collected. (This is true of the home object also.) It is the server's responsibility to eventually passivate the object in the server and allow the bean to be garbage-collected.

Conclusion
The Enterprise JavaBeans specification has received broad industry support. Major vendors, such as IBM, Oracle, Sybase and Netscape, have participated in the specification, and many more vendors plan to support EJB in their server and transaction-monitoring products. Because EJB was designed to be compatible with existing products, support for EJB should roll out rapidly. Several companies demonstrated early EJB support prototypes at the JavaOne conference in March, just weeks after the EJB 1.0 specification was published. One such company was IBM, which announced that they plan to support EJB across their software middleware and application servers, including Component Broker, TXSeries, CICS/390, MQSeries, DB/2, IMS and Lotus Domino, and that EJB is a key element of IBM's Network Computing Framework.

About the Author
Liane Acker develops Enterprise JavaBeans server runtime and tool technology for IBM. She has worked in the areas of object-oriented and distributed programming for six years, with particular focus on CORBA, JavaBeans and Enterprise JavaBeans. In 1992 she received her Ph.D. in computer science from the University of Texas at Austin. Liane can be reached at [email protected]

	

Listing 1.
 
public interface HotelRoom 
extends javax.ejb.EJBObject { 

public void reserve (int numberOfDays) 
throws java.rmi.RemoteException; 

// <more business methods only> 
} 

public interface HotelRoomHome 
extends javax.ejb.EJBHome { 

public HotelRoom create (RoomIdentifier roomNo) 
throws java.rmi.RemoteException, 
javax.ejb.CreateException; 

public HotelRoom findByPrimaryKey 
(RoomIdentifier roomNo) 
throws java.rmi.RemoteException, 
javax.ejb.FinderException; 

// <more create or find* methods only> 
} 
  

public class HotelRoomImpl 
implements javax.ejb.EntityBean { 

/* 
* implement business methods: 
*/ 
public void reserve (int numberOfDays) { 
// <business logic only> 
} 
// other methods from the HotelRoom interface 
  

/* 
* implement javax.ejb.EntityBean methods: 
*/ 
public void ejbActivate() {} // nothing 
public void ejbPassivate() {} // nothing 
public void ejbLoad() {} // nothing 
public void ejbStore() {} // nothing 
public void ejbRemove() {} // nothing 
public void setEntityContext 
(javax.ejb.EntityContext ctx) { 
this.ctx = ctx; 
} 
public void unsetEntityContext() { 
this.ctx = null; 
} 

/* 
* implement ejbCreate, ejbPostCreate, ejbFind* 
* methods corresponding to those in the 
* HotelHome interface: 
*/ 
public void ejbCreate (RoomIdentifier roomNo) { 
room_number = roomNo; 
} 
public void ejbPostCreate 
(RoomIdentifier roomNo) { 
// do nothing 
} 
public RoomIdentifier ejbFindByPrimaryKey 
(RoomIdentifier roomNo) 
{ 
// translate input params to primary key 
// (in this case, no computation required): 
return roomNo; 
} 

/* 
* public fields to be container-managed 
*/ 
RoomIdentifier room_number; 
// other fields, such as dates reserved. 
  

/* 
* private fields for internal use only 
*/ 

// EntityContext can be used by the bean to 
// explicitly control transactions & security: 
private javax.ejb.EntityContext ctx; 
} 

/* 
* Use JNDI to connect to the home: 
*/ 
javax.naming.Context ctx = 
new javax.naming.InitialContext(); 
HotelRoomHome home = (HotelRoomHome) 
javax.rmi.PortableRemoteObject.narrow( 
ctx.lookup("applications/hotel/rooms"), 
HotelRoomHome.class); 

RoomIdentifier key = new RoomIdentifier("351B"); 

/* 
* create a new record in the database: 
*/ 
HotelRoom room = home.create(key); 

/* 
* or get an object representing existing data: 
*/ 
room = home.findByPrimaryKey(key); 

/* 
* invoke business methods: 
*/ 
room.reserve(3); // reserve the room for 3 days 

/* 
* remove the record from the database: 
*/ 
room.remove(); 
  
      
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.