This part of the chapter presents information from an EJB client’s perspective. It explores the technologies necessary for accessing services supported by the EJB container. The following requirements are essential for achieving remote object access:
Understanding distributed objects and remote services that they support
Examining the technologies required for accessing remote, distributed objects
Learning Java Naming and Directory Interface (JNDI) procedures for locating a remote object
Knowing how to use RMI-IIOP and how it interacts with Enterprise JavaBeans
Delineating the differences between local and remote interfaces and their APIs
Exploring techniques for creating a client application
Writing a local nondistributed application that resides on a local machine and interacts with a single relational database does not require a remote interface nor does it present a significant challenge to the developer. However, this type of application has some severe drawbacks, namely, a lack of scalability and flexibility. It cannot process high-volume access to local objects.
In contrast, a distributed application presents numerous challenges. It requires the use of a container to manage system-level tasks; there is a need for managing and preserving state as well as facilitating resource pooling issues and thread management. It must be able to handle multiple requests from a host of client calls. In addition, the programmer must consider the problems involved in interacting with multiplatform operating systems and dealing with transmission protocols in a distributed enterprise environment. The location of remote objects must also be transparent.
Remote objects (also called distributed objects) represent units of discrete business logic built into one type of EJB or another. They can reside on more than one application server, and may span multiple platforms and operating systems. The trick is providing seamless accessibility to these remote objects for clients.
Fortunately, the J2EE specification version 1.3.1 offers viable solutions for remote object access, storing and retrieving mission-critical data to both legacy and web service-oriented services. The EJB container, rather than the bean developer, manages low-level transaction and state management details. The success of the interaction and interoperability between remote objects depends on both JNDI and RMI-IIOP technologies. Both technologies provide a standard, consistent methodology for locating and accessing remote objects. See Chapter 4 for a discussion of these two technologies, as well as an examination of the process of assembling EJBs into deployable JAR files. An analysis of the composition of deployment descriptors will reveal their role within the J2EE architecture.
It is possible for an EJB instance client to function as a servlet, JSP, or another EJB. Here is a typical sequence of events for accessing a remote object:
The client calls a business method in a remote component interface.
The client passes an object as a parameter.
The remote interface stub marshals the parameter before passing it to the EJBObject. This object is the proxy at the container.
The EJBObject skeleton must unmarshal the argument.
The container performs security, transaction, and life cycle services before the object is passed on to the corresponding business method and is executed on the bean instance.
The business method result is returned to the EJBObject.
Finally, the EJBObject marshals the result and transmits it back to the remote component interface. Then, the remote component interface unmarshals the object before the client receives the result.
With EJB 2.0, when the client session bean instance invokes business methods on an entity bean located in the same JVM, the client can use the local interface rather than the services of a remote object. This makes sense because there is no need for Remote Method Invocation.
Remote interfaces must implement RMI interfaces. This means that parameters and results of methods in remote home and component interfaces must provide support for RMI-IIOP. In this context, all arguments and results are passed by value. In addition, be aware that remote objects implement both remote component and home interfaces that are generated by the container when being deployed. They must throw a RemoteException.
In most cases, developers must use the PortableRemoteObject.narrow() method in order to cast to the desired Java object type. You will see an example of this in the BeanFactory code later in the chapter.
Local interfaces are available to clients if they reside within the same JVM as the bean instance. This obviates the necessity for providing a remote interface.
Objects that implement local home and component interfaces are not required to support RMI-IIOP. In addition, developers need not use the PortableRemoteObject.narrow() method in order to cast the reference to the desired type.
All parameters and results of local methods are passed by reference rather than by value. In addition, objects implementing the local home and component interfaces are generated by the container at deployment time. They do not need to throw a RemoteException.
Stateful session beans keep client information between method invocations. It is safe to assume they are appropriate for preserving state in a shopping cart application. Stateful session beans are also used for managing interaction with other EJBs. Frequently, a session bean may interact with several other beans to fulfill a client task. For example, an IFCE stateful session bean that creates a consumer order for purchasing euros will typically call other beans to receive a currency price update from Reuters. The bean will also check with other branches to determine whether they have the amount of currency requested by the client. It will also invoke a bean to check a client’s account status, and so on.
Stateful session beans have a complex life cycle. They exist in the following states:
Does Not Exist
Method Ready Transaction
Both client and container affect the state and their transition from one state to another. For example, the initial state is Does Not Exist. When a client invokes the Create <Method>, which is declared in the home interface, the container executes the following steps:
Create the EJBObject and SessionContextObject
Create the stateful SessionBean instance
Call the setSessionContext method followed by a call to its associated matching ejbCreateMethod
Upon completion of the ejbCreate<Method>, the stateful SessionBean instance is now in the Method Ready state. In this state, the stateful SessionBean can execute any nontransactional business methods for the client.
The container is responsible for managing the stateful SessionBean life cycle. In addition to setting the timeout value, the container sets a passivated time for bean instances when they are created. A passivated time represents the maximum time that a stateful session bean can reside continuously in memory between repeated client accesses. Both of these values allow the container to provide memory management. When the container is low on memory, it may utilize the ejbPassivation time to choose stateful SessionBean instance candidates, serialize them, and free up memory.
A passivated bean instance can transition to a Does Not Exist state if it exceeds the timeout value. In addition, a container may not interrupt a session bean in the middle of a transaction.