Book Home Java Enterprise in a Nutshell Search this book

7.2. EJB Roles

In Chapter 3, "Remote Method Invocation", I described two fundamental roles in the RMI environment: the client of the remote object, and the object itself, which acts as a kind of server or service provider. These two roles exist in the EJB environment as well, but EJB adds a third role, called the container provider. The container provider is responsible for implementing all the extra services for an EJB object that I mentioned earlier: transaction processing, security, object persistence, and resource pooling. If you're familiar with CORBA, you can think of the EJB container as being roughly equivalent to the ORB in CORBA, with a few of the CORBA services thrown in as well. In EJB, however, the container is strictly a server-side entity. The client doesn't need its own container to use EJB objects, but an EJB object needs to have a container in order to be exported for remote use. Figure 7-1 shows a conceptual diagram of how the three EJB roles interact with each other.

figure

Figure 7-1. The basic roles in an EJB environment

7.2.1. The EJB Client

An EJB client uses remote EJB objects to access data, perform tasks, and generally get things done. In the EJB environment, the first action a client performs is to find the home interface for a type of EJB object that it wants to use. This home interface is a kind of object factory, used to create new instances of the EJB type, look up existing instances (only when using entity EJB objects, discussed later), and delete EJB objects. This is a bit different from RMI, where the client first has to get a direct handle to an existing RMI object. In many RMI applications, however, this first RMI object is a kind of object factory that creates other RMI object references. So, in a sense, the use of home interfaces in EJB is just formalizing the role of factory objects in distributed component applications.

EJB home interfaces are located by clients using JNDI (see Chapter 6, "JNDI", for more information). An EJB server publishes the home interface for a particular EJB object under a particular name in a JNDI namespace. The EJB client needs to specify the JNDI server and the name that the EJB home interface is stored under in order to start things off. The following code shows a simple EJB client that uses remote Person beans:

import javax.ejb.*;
import javax.naming.*;
import java.rmi.*;
import java.util.Properties;

public class PersonClient {
  public static void main(String[] args) {
    String name = args[0];

    try {
      // Get a JNDI context for our EJB server (EJBHome, in this case)
      Properties p = new Properties();
      p.put(Context.INITIAL_CONTEXT_FACTORY,
            "com.ejbhome.naming.spi.rmi.RMIInitCtxFactory");
      // Add URL, host or port options, if needed...;
      Context context = new InitialContext(p);

      // Get the home interface for Person beans
      PersonHome pHome =
        (PersonHome)context.lookup("People");

      // Create a named person
      Person person = pHome.create(name);

      // Use the remote stub interface to access the person's data
      . . .
    }
    catch (NoSuchPersonException nspe) {
      System.out.println("Invalid person: " + name);
    }
    catch (Exception e) {
      System.out.println("Error while creating/using person.");
    }
  }
}

We'll examine the details of this client a bit later in the chapter, but the example shows the fundamental steps an EJB client performs:

7.2.2. The Enterprise JavaBeans Object

If you develop your own EJB object, you need to provide three Java interfaces/classes in order to fully describe your EJB object to an EJB container:

The remote interface and the object implementation are similar to the corresponding RMI interfaces. A client issues method requests through a stub derived from the remote interface and eventually these requests make their way to the corresponding bean instance on the server. The home interface is a new twist: it acts as a bean factory, providing a way for a client to create, locate, and destroy EJB objects that it uses. With the home interface in the picture, the remote interface acts as the interface the client uses to interact with EJB objects, and the implementation is where the object itself does its thing.

Here is an example home interface for the Person bean used in the previous example:

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

public interface PersonHome extends EJBHome {
  // Create a new (nameless) person
  public Person create() throws RemoteException;

  // Create a named person.  
  // Throws an exception if the person can't be found.
  public Person create(String name)
    throws RemoteException, NoSuchPersonException;

  // Lookup a Person by name (the "primary key")
  public Person findByPrimaryKey(PersonPK key)
    throws RemoteException, FinderException;

  // Lookup people with a given string in their name.
  public Enumeration findByPartialName(String fragment)
    throws RemoteException, FinderException;
}

This home interface includes methods to create Person beans and to find them if they already exist on the server. The remote interface for our Person bean is shown here:

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

public interface Person extends Remote, EJBObject {
  public String getName() throws RemoteException;
  public void setName(String name) throws RemoteException;
}

This interface shows the business methods that are available to clients. When a client gets a reference to a bean through the PersonHome interface, it is given a stub that implements the Person interface.

The EJB object implementation needs to implement all the business methods in the remote interface, plus some methods used by the container to tell it about various events in its lifetime. The EJB object does not need to implement the remote interface, which is another new twist compared to RMI, where the server object always implements the remote interface. In EJB, the container arranges for method calls on the remote interface to be transferred to the EJB object. You just need to ensure that the EJB object has methods that match the signatures of the methods in the remote interface. We'll see an example of EJB object implementation a bit later.

Various pieces of these Java classes (home, remote, and implementation) are provided for the sake of the client, to allow a client to create EJB objects and call remote methods on them. Other pieces are provided for the EJB container, to allow it to notify the EJB object about transaction- and persistence-related events, for example.

In addition to the interfaces that describe the EJB object type, an EJB object also provides deployment descriptors to its containers. The deployment descriptors tell the container the name to use for registering the bean's home interface in JNDI, how to manage transactions for the bean, the access rights that remote identities are given to invoke methods on the EJB, and how persistence of the EJB objects should be handled. The container does all the heavy lifting with regard to providing these services, but the EJB object has to tell the container how it would prefer to have these services managed.

There are two fundamental types of Enterprise JavaBeans: session beans and entity beans.[2] A session bean is accessed by a single client at a time and is nonpersistent. It lives for a specific period of time (a session), and then gets removed by the server. An entity bean, on the other hand, represents a data entity stored in persistent storage (e.g., a database or filesystem). It can be accessed by multiple clients concurrently and is persistent beyond a client session or the lifetime of the EJB server.

[2]In Version 1.0 of the EJB specification, support for entity beans is optional in compliant EJB servers.

To illustrate the difference between session and entity beans, suppose you're building an online banking system using EJB components. An automated bank teller, which reports on account balances and executes deposits and withdrawals on specified accounts, could be implemented as a session bean. A single client uses the teller bean to perform services on bank accounts that are maintained in some separate persistent store (the bank's database). A EJB object that directly represents a bank account, however, should be an entity bean. Multiple clients can access the account to perform transactions, and the state of the account entity should be persistent across the lifetime of the online banking server.

7.2.3. The EJB Container

Most readers need to be familiar only with EJB containers from the perspective of an EJB client or an EJB object. For example, a Java application server that you might use to deploy an EJB-based application provides an implementation of the EJB container role. EJB-enabled application servers, with their own EJB containers and deployment tools, are available from Weblogic/BEA, Bluestone, IBM, Netscape, and Art Technology Group, among others.

The EJB container represents the value-added features of EJB over standard remote objects built using RMI or CORBA. The EJB container manages the details of transactional processing, resource pooling, and data persistence for you, which reduces the burden on client applications and EJB objects and allows them to deal with just the business at hand.

An EJB application server can contain multiple EJB containers, each managing multiple EJB objects. In this chapter, I'll refer to EJB servers and EJB containers somewhat interchangeably, depending on the context. In general, though, the container is strictly the runtime elements that interact directly with your EJB objects to provide client proxy services and notifications, while the server is the other glue outside the core EJB standard that integrates the EJB containers into a larger application management structure of some kind.

An EJB container is the heart of an EJB environment, in the same way an ORB is the heart of a CORBA environment. The container registers EJB objects for remote access, manages transactions between clients and EJB objects, provides access control over specific methods on the EJB, and manages the creation, pooling, and destruction of enterprise beans. The container also registers the home interface for each type of bean under a given name in a JNDI namespace, allowing remote clients to find the home interfaces and use them to create enterprise beans.

Once you provide the EJB container with the home and remote interfaces and the implementation class for your bean, along with a deployment descriptor, the container is responsible for generating the various classes that connect these components, as shown in Figure 7-2. The home and remote interfaces you provide are RMI Remote interfaces; the container generates both the client stubs and the server-side implementation for these interfaces. When a client looks up a bean's home interface through JNDI, it receives an instance of the home stub class. All methods invoked on this stub are remotely invoked, via RMI, on the corresponding home implementation object on the EJB server. Similarly, if the client creates or finds any beans through the home stub, the client receives remote object stubs, and methods invoked on the stubs are passed through RMI to corresponding implementation objects on the server. These remote objects are linked, through the EJB container, to a corresponding enterprise bean object, which is an instance of your bean-implementation class. Optionally, the EJB container may also generate a container-specific subclass of your bean implementation (e.g., if it wants to augment some of your bean methods to facilitate synchronization with the container).

figure

Figure 7-2. Relationship of bean-provider classes and container-generated classes

The container receives client requests to create, look up, and/or remove beans. It either handles them itself or passes the requests to corresponding methods on the EJB object. Once the client obtains a reference to a remote interface for an EJB object, the container intercedes in remote method calls on the bean, to provide the bean with required transaction management and security measures. The container also provides support for persistence of enterprise beans, either by storing/loading the bean state itself or by notifying the bean that it needs to store or reload its state from persistent storage.

A container can maintain multiple EJB objects and object types during its lifetime. The container has some freedom to manage resources on the server for performance or other reasons. For example, a container can choose to temporarily serialize a bean and store it to the server filesystem or some other persistent store; this is called passivating a bean. The EJB object is notified of this and given a chance to release any shared resources or transient data that shouldn't be serialized. The bean is also notified after it is activated again, to allow it to restore any transient state or reopen shared resources.

An EJB container can make any EJB object type available for remote use. When you deploy an EJB object within an EJB server, you can specify how the container should manage the bean during runtime, in terms of transaction management, resource pooling, access control, and data persistence. This is done using deployment descriptors, which contain parameter settings for these various options. These settings can be customized for each deployment of an EJB object. You might purchase an EJB object from a vendor and deploy it on your EJB server with a particular set of container management options, while someone else who purchased the same bean can deploy it with a different set of deployment options. We discuss the details of the runtime options available in deployment descriptors and how to use them later in this chapter, when we talk about deploying EJB components.



Library Navigation Links

Copyright © 2001 O'Reilly & Associates. All rights reserved.