wiley-logo-sm.gif
> wiley.com

Programming with Enterprise
JavaBeans, JTS, and OTS

Building Distributed Transactions with Java and C++

 

Chapter 5

Understanding
Enterprise JavaBeans

In this chapter we present Sun’s Enterprise JavaBeans (EJB) specification. The specification is primarily focused on developers of EJB containers and servers, which form the infrastructure in which an enterprise bean is deployed. We present the EJB specification from a programmer’s or, in EJB terms, an enterprise bean provider’s and application assembler’s point of view.

First we investigate what Enterprise JavaBeans are and what their purpose is, and in the second section, we explain the EJB infrastructure. The main focus of the chapter is on APIs used by an enterprise bean provider and assembler. In the section "EJB Development," we explain those interfaces and classes defined by the EJB specification and illustrate their use.

The APIs defined for the deployer are under change as we write. While the EJB specification 1.0 uses serialized Java objects to capture deployment information, the subsequent release defines XML as the language for deployment information. However, we do not expect the deployer to be directly confronted with any of these formats when using an EJB product. Commercially relevant EJB servers must provide tool support in the form of wizards or similar tools to handle deployment information. Hence we concentrate in the section"EJB Deployment" on the explanation of the deployment properties and policies.

The EJB specification does not provide much detail about the enterprise bean assembly. In the section"Application Assembling," we explain how an application assembler uses the EJB APIs and the Java Naming and Directory Interface (JNDI) to build distributed enterprise applications.

Finally, we present how EJB and CORBA can be integrated. The EJB specification 1.0 defines how CORBA clients, implemented in any of the programming languages that CORBA defines a mapping from IDL to, can interact with enterprise beans. However, that is another area of the specification under revision and thus we concentrate on the general aspects such as protocol interoperability, transaction coordination, and security.

We return to Enterprise JavaBeans development in Chapter 6,"Programming with EJB," where we implement a comprehensive example.

Why Enterprise JavaBeans?

Distributed systems are complex. Building distributed applications, particularly when dealing with distributed transactions, is difficult and requires highly specialized and experienced people with skills in different areas.

Enterprise JavaBeans is an approach to overcome this problem. The idea is to apply the divide-and-conquer approach to distributed systems. In this context, it means to divide the building of a distributed application into different tasks. These tasks can then be executed by different people with different levels and different areas of expertise. The main benefit for an application developer is that certain tasks are taken over by vendors. EJB containers provide a number of features that in the past had to be addressed by the application programmer.

The Enterprise JavaBeans specification identifies the following roles that are associated with a specific task in the development of distributed application.

Enterprise Bean Provider is typically an expert in the application domain; for example, in the financial or telecommunications industry. The bean provider implements the business task without being concerned about the distribution, transaction, security, and other nonbusiness-specific aspects of the application.

Application Assembler is also a domain expert. The application assembler composes an application from various prefabricated building blocks (that is, enterprise beans) and adds other components such as GUI clients, applets, and servlets to complete the application. While composing an application, an assembler is only concerned with the interfaces to enterprise beans, but not with their implementation.

Deployer is specialized in the installation of applications. The deployer adapts an application, composed of a number of enterprise beans, to a target operation environment by modifying the properties of the enterprise beans. The deployer’s tasks include, for example, the setting of transaction and security policies and JNDI names by setting the appropriate properties in the deployment descriptor, and the integration with enterprise management software.

EJB Server Provider is typically a vendor with expertise in distributed infrastructures and services. The server provider implements a platform, which facilitates the development of distributed applications and provides a runtime environment for them. There can also be specialized containers that wrap a certain class of legacy applications or systems.

EJB Container Provider is an expert in distributed systems, transactions, and security. A container is a runtime system for one or multiple enterprise beans. It provides the glue between enterprise beans and the EJB server. A container can be both, prefabricated code as well as a tool, that generates code specific for a particular enterprise bean. A container also provides tools for the deployment of an enterprise bean and hooks into the application for monitoring and management.

System Administrator is concerned with a deployed application. The administrator monitors the running application and takes appropriate actions in the case of abnormal behavior of the application. Typically, an administrator uses enterprise management tools that are connected to the application by the deployer through the hooks provided by the container.

Note that the current version of the EJB specification does not define nor exactly draw the line between the two components. In fact, people often refer to it as a single entity. The current specification also does not define APIs for the management of deployed enterprise beans.

Figure 5.1 illustrates the relationships between the various components that are provided by the people or vendors that fulfill the roles described earlier. A "traditional" application programmer now becomes an enterprise bean provider and application assembler, which allows her or him to focus on the business problem. The deployer defines and sets the deployment policies when installing the enterprise bean. The complexity of implementing mechanisms for executing the deployment policies is delegated to specialized vendors. Although the complexity of distributed applications cannot be reduced in total, the application programmer’s job becomes easier as much complexity is addressed by EJB server and container providers.

Figure 5.1  Tasks, roles, and components.

The EJB specification achieves the aforementioned goals by introducing a number of predefined design patterns and naming conventions. This restricts the freedom in the application architecture, but allows the container and service providers to make assumptions about the application design and support them in an efficient manner.

There are three major design patterns for building object-based multitier distributed systems: stateless server approach, the factory/session model, and the persistent object approach. The stateless server is an object that provides certain functionality through its operations without keeping conversational state. That means that clients cannot refer to state information provided in previous operations on the same object.

The session-oriented design creates an object in the middle tier, a session, that is acting as an agent for the client. Typically, the lifetime of a session object is determined by the client and the server program that is hosting it. A client can remove the object once it is finished with it. The server can timeout a session object, and when the server terminates, references to the session object become invalid.

The persistent object design models wraps a certain piece of data (typically stored in a database) and provides operations to manipulate this data. Persistent objects are shared among multiple clients. The lifetime of a persistent object is determined by the lifetime of the data storage, which contains its data.

The EJB specification takes these three design patterns and defines them as Stateless Session Bean, Stateful Session Bean, and Entity Bean. The stateless session bean is modeled after the stateless server approach, the stateful session bean after the session-oriented design approach, and the entity bean after persistent object design. For each design, it defines a number of interfaces and naming conventions, which we explain in detail next.

EJB Infrastructure

The container and service providers implement the EJB infrastructure. This infrastructure deals with distribution aspects, transaction management, and security aspects of an application. The EJB specification only defines the Java APIs, which determine the various features, and does not prescribe which technology, platforms, protocols, and so forth are used to implement them.

Figure 5.2 illustrates the various requirements for the EJB infrastructure. In fact, we have added a few requirements beyond those from the EJB specification that we see as essential for successful enterprise applications. The EJB infrastructure must provide communication channels to clients and other enterprise beans. Although not required by the EJB specification, communication channels for clients’ access beans via the Internet must be secured. The EJB infrastructure must also be able to enforce access control to enterprise beans.

Figure 5.2  Enterprise beans, containers, and servers.

The persistence of the data contained by enterprise beans must be ensured. An EJB infrastructure must provide integration capabilities to existing systems and applications to be useful in an enterprise computing environment. This requirement is stated in the specification, but no APIs are provided. All communication to and from a bean can be part of a distributed transaction that needs to be managed by the EJB infrastructure. For a successful deployment, the EJB infrastructure must provide hooks into a distributed application management tool. Again, the specification does not define any management APIs.

The EJB specification leaves it up to the container and EJB server providers on how to satisfy these requirements. However, it defines a number of interfaces and conventions on the container level, which we present next. Later in the section we review different EJB container and server implementations and investigate how they satisfy the requirements stated earlier.

Container

The container is probably the single most important concept in the enterprise beans approach as it provides the most benefit to the developer. Object-based middleware platforms like CORBA or RMI free a distributed application developer from the networking aspects of the application by providing mechanisms for object location, data marshaling, and so forth. The concept of a container takes this idea a step further by simplifying other nontrivial aspects of a distributed application such as security, transaction coordination, and data persistence.

Once an enterprise bean is ready for deployment, it is packed in a standard Java archive file, called an ejb-jar file. The ejb-jar file can contain one or multiple enterprise beans. For each enterprise bean, it contains its interfaces, classes, and a deployment descriptor. The ejb-jar file also contains a manifest file that identifies the enterprise beans in the file.

The enterprise bean provider has to supply three things to the ejb-jar file:

  • The enterprise bean’s remote interface to the enterprise bean, which specifies the application-specific methods

  • Its home interface, which helps to create and locate instances of the enterprise bean

  • The implementation of the application semantics of the enterprise bean

  • The policies and properties that determine the execution of a particular enterprise bean are provided by the deployer using the deployment descriptor. The EJB1.0 specification defines the deployment descriptor as a serialized instance of the class javax.ejb.deployment. SessionDescriptor or javax.ejb.deployment.EntityDescriptor. This API has been deprecated in the subsequent version and XML is used instead for defining deployment descriptors. Details on the deployment descriptor are given later in the chapter.

    Deploying an enterprise bean means to install the ejb-jar file into a container, as illustrated in Figure 5.3. The installation process deals with the following issues:

  • Gluing the different pieces of the enterprise bean together

  • Registration of the enterprise bean with a name service

  • Providing access to the enterprise bean through the EJB server’s communication system

  • Executing the transaction management and security policies

    Figure 5.3  Enterprise beans and containers.

    There can be any number of different enterprise beans installed in a container. Besides the installation and execution of an enterprise bean, a container also provides tools for the deployment of an enterprise bean, which are explained in the section,"EJB Deployment," later in the chapter. The interfaces to a container are currently not standardized in the EJB specification.

    Identifying an Enterprise Bean

    A client always invokes methods on an enterprise bean’s remote interface. This interface is referenced by a portable remote object reference. Additionally, an enterprise bean can be referenced by a handle, which is a more abstract identifier.

    Portable Remote Object Reference

    The portable remote object reference identifies remote interfaces and the home interfaces of enterprise beans. It is an opaque data type that contains all the necessary information to enable a client to make invocation on the interfaces. Similar to a CORBA Interoperable Object Reference (IOR), it comprises address information such as IP addresses, port numbers, and information about the type and the instance of the referenced object.

    Handle

    A handle is a more abstract way of referencing a remote object to an enterprise bean. It is defined by the following interface that must be implemented by all enterprise bean handles.

    public interface javax.ejb.Handle {

    public abstract EJBObject getEJBObject()
    throws java.rmi.RemoteException;

    }

    It can be used to persistently store a reference to an EJB object by serializing an instance of the class that implements the handle interface, which is similar to a stringified CORBA IOR. Therefore, implementations of the interface must also implement the interface java.io.Serializeable. Handle implementations are typically provided by a container.

    Container Implementation

    The EJB specification neither defines the interface to a container nor does it prescribe the technologies used to implement a container. In this section we give an example of an EJB container based on CORBA technology and discuss the concept of a specialized container. The main purpose of this is to illustrate how the magic functionality provided by the container can be implemented.

    CORBA Container Implementation

    A CORBA-based implementation of an EJB container is typically based on the following components (summarized in Table 5.1): CORBA core and IIOP as the communication infrastructure, OTS for the transaction management, a JNDI wrapper of the CORBA Naming Service, and the CORBA Security Service. Figure 5.4 shows how these CORBA components fit into the EJB container picture.

    Table 5.1  EJB Server with CORBA Technology

    issue CORBA Technology

    Communication protocol RMI over IIOP (including OTS transaction id in the service context)

    JNDI JNDI over CORBA Naming Service

    Transactions CORBA Object Transaction Service

    EJB activation and deactivation POA

    Security IIOP over SSL

    Figure 5.4  CORBA container.

    A CORBA-based container implementation is a native Java implementation using OMG’s Java-to-IDL mapping. Besides the Java platform features, availability, and portability, CORBA provides one major additional advantage. The interoperability between enterprise beans is guaranteed by OMG’s industry standards: IIOP and standardized IDL interfaces for underlying services, specifically OTS.

    Furthermore, CORBA has been designed and proven to be a very efficient mechanism for integrating legacy systems into new applications. Object Transaction Service’s compliance with the X/A allows for seamlessly accessing heterogeneous resources and integration with legacy systems.

    CORBA implementations have also proven the scalability and robustness expected for enterprise systems. CORBA is deployed today in critical business applications in intranet, extranet, and Internet environments as well as backend systems. These deployments are across all major industry sectors, including finance, telecommunications, and healthcare.

    The examples of enterprise beans we present in this book have been deployed in a CORBA-based container, the Inprise EJB Server. This EJB server is based on Visibroker for Java, Visibroker Naming, Visibroker ITS, and Visibroker SSL. JBuilder integrates tool supports for development, deployment, and debugging aspects. Inprise AppCenter provides the management of an EJB application deployed in the Inprise container.

    Specialized Container Implementation

    A specialized container is an EJB wrapper around a legacy system—the container and the enterprise beans installed become a single entity. Arbitrary enterprise beans may not necessarily be installable into such a container. The container would, however, expose the functionality of the legacy system through EJB home and remote interfaces.

    An enterprise bean is a proxy for the program, which is executed by a legacy system. For example, the only enterprise beans installed in this container can be proxies, which communicate, for example, via CICS to a mainframe program. Instead of having independent enterprise bean providers, the vendor, who provides the container, would also provide tools to automatically generate enterprise beans, which interface with the backend system. Specialized containers require a standard protocol for communication and transaction control. Otherwise the use would be quite limited.

    Figure 5.5 shows a possible scenario of a specialized container. It depicts the different components used by a container front-ending CICS. The remote access to the enterprise bean would be via RMI (over IIOP). The bean is registered with JNDI, using any JNDI implementation. The security mechanisms and the transaction management are tightly integrated with the backend systems. Mainframes have sophisticated access control mechanisms, which would be wrapped with Java Security APIs. Transactions could be managed by CICS, or via integration with JTS.

    Figure 5.5  Specialized container implementation.

    EJB Development

    The enterprise bean provider is concerned with a number of tasks:

  • Defining the Remote Interface

  • Defining the Home Interface

  • Defining the Primary Key class (for entity beans)

  • Implementing the enterprise bean; that is, the functionality defined in the remote and home interface

  • Figure 5.6 illustrates the relationships among the remote interface, the home interface, the implementation of the enterprise bean, and other components supplied by the infrastructure.

    Figure 5.6  Components of an enterprise bean.

    The EJB provider defines the remote and the home interface and implements the enterprise bean. Every enterprise bean must have a home interface, which always provides methods to locate or to create instances of the remote interface. The remote interface specifies methods according to the application logic encapsulated by the enterprise bean.

    An EJB object is an implementation of functionality declared in the enterprise bean’s home and remote interface. The remote and home interface and the bean implementation are in no formal (inheritance or implementation) relationship; however, their methods must match according to a number of rules and naming conventions defined by the EJB spec. Application-specific methods must have the same signatures. The container provides the glue between the home and remote interface and the enterprise bean implementation class where the bean provider defines the semantics of the enterprise bean. The container ensures, at compile time or runtime, that the remote interface and the enterprise bean implementation match.

    Figure 5.6 only shows the relationships between interfaces and classes. The glue between the home and remote interface and the enterprise bean implementation is not specified by the EJB specification, and its realization is left to the container provider.

    Remote Interface

    An enterprise bean has a remote interface that defines the application-specific operations. Clients to the enterprise bean access it through its remote interface.

    An enterprise bean’s remote interface is a public Java interface extending the interface javax.ejb.EJBObject, which is the base interface of all remote interfaces.

    package javax.ejb;

    public interface EJBObject extends java.rmi.Remote {

    EJBHome getEJBHome() throws java.rmi.RemoteException;

    Object getPrimaryKey() throws java.rmi.RemoteException;

    void remove() throws java.rmi.RemoteException, RemoveException;

    Handle getHandle() throws java.rmi.RemoteException;

    boolean isIdentical (EJBObject p0) throws java.rmi.RemoteException;

    }

    The method getEJBHome() allows you to get the associated home interface. For entity beans, you can get the primary key of the entity bean using the method getPrimaryKey(). The remove() method deletes the enterprise bean; we explain details in the context of the life cycle of the various types of enterprise beans. The method getHandle returns the handle, as explained earlier, of the enterprise bean, and the isIdentical() allows you to compare enterprise beans.

    The remote interface defines public methods, which can be invoked by clients. All methods must throw the exception java.rmi.RemoteException.

    We already defined a remote interface for the ATM session bean in Chapter 1, "Quick Start to EJB, JTS, and OTS." The parts of the following interface definition that are in bold type are required by the EJB specification.

    package vogel.transaction.chapter1.ejb;

     

    public interface Atm extends javax.ejb.EJBObject {

     

    public void transfer(

    String source, String target, float amount )

    throws java.rmi.RemoteException, InsufficientFundsException;

    }

    The definition of the remote interface of session and entity beans follows the same rules.

    Home Interface

    An enterprise bean’s home interface controls the life cycle of a bean. It provides operations to create, find, and remove an EJB object; that is, an instance of enterprise bean. Session and entity beans have different life cycles due to their respective design patterns. Consequently, the types of their home interfaces must define different methods.

    In either case, the home interface defines the interface and the implementation is provided by the container and by the enterprise bean implementation class.

    Home Base Interface

    Every home interface extends the interface javax.ejb.EJBHome. This interface is defined as follows:

    package javax.ejb;

     

    public interface EJBHome extends java.rmi.Remote {

    void remove(Handle handle)
    throws java.rmi.RemoteException, RemoveException;

     

    void remove(Object primaryKey)

    throws java.rmi.RemoteException, RemoveException;

     

    EJBMetaData getEJBMetaData()

    throws RemoteException;

    }

    There are two remove() methods provided to remove EJB object instances. The first remove() method removes an instance identified by a handle, the second one by a primary key. A handle is a unique EJB object identifier, which we introduced earlier. A handle has the same lifetime as the EJB object it is referencing. In the case of an entity object, a handle can be valid for multiple instantiations of an EJB object; for example, it is valid even if a server crashed that hosted the EJB object, or when the EJB object moves between different servers and machines. A serialized handle is a concept very similar to a stringified CORBA object reference.

    The other remove() operation on the EJBHome interface uses a primary key to determine the object to be removed. A primary key can be of any Java type extending the Java Object class and must implement the Java Serializable interface. Primary keys are the main means of identification for entity beans. A primary key is typically a key in a database table which uniquely defines the data, represented by the entity object.

    The method getEJBMetaData() returns metadata of the EJB object. The metadata type is defined by a Java interface, which provides methods to obtain the EJBHome interface, the type (class) of the home and the remote interface, as well as the type of the primary key. It also provides a method to find out if the object hosted by this home interface is a session or entity bean.

    package javax.ejb;

     

    public interface EJBMetaData {

     

    EJBHome getEJBHome();

     

    Class getHomeInterfaceClass();

     

    Class getRemoteInterfaceClass();

     

    Class getPrimaryKeyClass();

     

    boolean isSession();

     

    }

    Session Bean Home

    The session bean pattern mandates that each client has an individual session bean instance. The home interface becomes a session bean factory by defining one or more create() methods. The EJB specification defines a naming convention for these create() methods:

  • Return type is the remote interface type

  • Method name is always"create", parameters can vary

  • Throws the exception java.rmi.RemoteException

  • Throws javax.ejb.CreateException

  • Parameters of the method are used to initialize the new EJB object

  • The following example shows different create methods at a session home interface. Required parts are shown in bold.

    package vogel.transaction.chapter1.ejb;

     

    public interface AtmHome extends javax.ejb.EJBHome {

     

    Atm create()

    throws java.rmi.RemoteException, javax.ejb.CreateException;

    Atm create( Profile preferredProfile )

    throws java.rmi.RemoteException, javax.ejb.CreateException;

    }

    Note that session home interface must not define finder methods to locate objects, as stateful session beans are intended to be used only by their creator.

    Entity Bean Home

    Similar to the session’s home interface, the entity home interface can provide create methods following the same pattern. However, the primary means of locating an entity bean is by using finder operations, since entity beans are long lived and typically already exist and a client just has to find the one it wants to invoke.

    An entity home interface has to provide the default finder method, which returns an object of the bean’s remote interface type and takes primary key as an argument. The type of the primary key can be of any Java type, which extends the Java Object class. As part of the deployment description, you tell the container the type of the primary key.

    <entity bean’s remote interface> findByPrimaryKey(

    <primary key type> key )

    throws java.rmi.RemoteException, FinderException;

    The home interface can define further find methods according to the following conventions:

  • Return type is the remote interface type or a collection type, which has the remote interface type as the content type

  • Method always starts with the prefix"find"

  • Throws the exception java.rmi.RemoteException

  • Typically throws the exception javax.ejb.FinderException

  • Parameters determine one or more EJB objects

  • Additionally, an entity bean’s home interface can provide one or more create() methods, which returns an object reference of the bean’s remote interface type. The arguments are application specific.

    The create methods must comply with the following conventions:

  • Return type is the remote interface type

  • Method name is always"create", parameters can vary

  • Throws the exception java.rmi.RemoteException

  • Throws the exception javax.ejb.CreateException

  • The following example shows different types of finder and create methods. Required parts are shown in bold.

    package vogel.transaction.chapter1.ejb;

     

    public interface AccountHome extends javax.ejb.EJBHome {

     

    Account create( String accountId )

    throws java.rmi.RemoteException, javax.ejb.CreateException;

     

    Account create( String accountId, float initialBalance )

    throws java.rmi.RemoteException, javax.ejb.CreateException;

     

    Account findByPrimaryKey( String key )

    throws java.rmi.RemoteException, javax.ejb.FinderException;

     

    Enumeration findBySocialSecurityNumber( String socialSecurityNumber )

    throws java.rmi.RemoteException, javax.ejb.FinderException;

     

    }

    Bean Implementation

    The bean implementation is the principal work of a bean provider as it contains all of the application-specific semantics. A bean class implements the SessionBean or the EntityBean interface depending on its type. These interfaces extend the enterprise bean base interface EnterpriseBean.

    Enterprise Bean Interface

    The enterprise bean interface just defines a common base interface; there are no methods defined.

    package javax.ejb;

     

    public interface EnterpriseBean extends Serializable {}

    Session Bean

    A session bean implementation must implement the session bean interface and comply with a number of rules and naming conventions that define the relationship of this class to the remote and the home interface.

    Session Bean Interface

    The session bean interface SessionBean extends the interface EnterpriseBean. The methods of the session bean interface are closely associated with the life cycle of a session bean. To fully understand the semantics of the methods, we first have to take a look at the life cycle of session beans. During this process we introduce the methods of the session bean interface. Note that a session implementation must also implement methods corresponding to the home interface and to the remote interface. The home interface’s create() methods have corresponding ejbCreate() methods in the implementation class.

    The EJB specification defines stateless and stateful session beans.

    Stateless session bean.  The bean does not contain conversational state between method invocations. As a consequence, any session bean instance can be used for any client.

    Stateful session bean.  The bean contains conversational state that is kept across method invocations and transactions. Once a client has obtained a specific session bean, it must use this instance for the lifetime of the session. A client can, however, have multiple, distinguished sessions and hence multiple session bean instances.

    Life Cycle of a Stateless Session Bean

    The life cycle of a stateless session is pretty simple, as shown in Figure 5.7. A new instance is created and the methods setSessionContext() and ejbCreate() are invoked on the session object. Now the new instance is in a pool of instances, which are ready to be invoked. Since the stateless session objects do not keep state, any of the instance can be used for any of the incoming method invocations. When an instance is removed from that pool, the method ejbRemove() is invoked on the session object.

    Figure 5.7  Life cycle of a stateless session bean.

    Note that the creation and removal of session bean instances are not related to the create() and remove() methods on the home/remote interface. The life cycle of stateless session beans is governed by container policies.

    Life Cycle of a Stateful Session Bean

    Typically, the life of a session bean starts when a client invokes a create() method on the session bean’s home interface (see Figure 5.8). The implementation of the home interface is provided by the container, based on the session bean implementation class. The container creates a new instance of the session bean, initializes it, and returns an object reference back to the client. During this process, first the method setSessionContext() and then the method ejbCreate…() are invoked on the session bean implementation (which implements the session bean interface). The bean provider can use these methods to initialize the session bean. Details of these methods are given later in the chapter. The state of the session bean is now method ready.

    Figure 5.8  Life cycle of a stateful session bean.

    Once a client invokes a remove() method on the remote or home interface, the corresponding ejbRemove() method is invoked on the EJB object, to allow the bean provider to add application-specific cleanup code. Once the invocation is completed, the object is in a nonexistent state again. When a client tries to invoke a method on a session object in this state, the exception java.rmi.NoSuchObjectException is thrown by the container.

    The container can deactivate the session bean instance, typically for resource management reasons. For example, when a session object has not been used by a client for a certain time, the container stores reference and state of the session object on disk and frees the memory allocated by the bean. However, files or other operating system controlled resources that may have been opened by the session bean must be explicitly handled in the implementation. This can be done in the ejbActivate() and ejbPassivate() methods, which are triggered by the container. The instance is typically reactivated when the client makes the next call on the session bean’s reference it holds. Then the container recreates the session object in memory. CORBA’s object adapter provides similar activation and deactivation mechanisms.

    When a method is invoked on the object in a transactional context, there are again a number of interception points for the bean provider. They are defined in the interface SessionSynchronization, which is explained below. The use of this interface is optional. The method afterBegin() is invoked after a method is invoked on the remote interface. That puts the EJB object in the state method ready in TX. Once the object is in this state it will accept the invocation of the method in this transaction context and only this. The commit of the transaction triggers the invocation of two methods, beforeCompletion() and afterCompletion( true ), on the EJB object. In the case of a rollback, the method afterCompletion( false ) is invoked on the session object. As a result of the commit or rollback, the session object will be back in the method ready state.

    A session bean’s lifetime is bound to the lifetime of the container in which it is installed. Once the process, or JVM, in which the container is executed terminates, the session bean’s reference usually becomes invalid. Once a session bean was passivated and its state persisted, a smart EJB server could re-activate the session bean in a different container.

    SessionBean Interface

    The session bean interface defines the methods all session beans must implement.

    package javax.ejb;

     

    public interface SessionBean extends EnterpriseBean {

     

    void setSessionContext(SessionContext sessionContext)

    throws RemoteException;

     

    void ejbRemove() throws RemoteException;

     

    void ejbActivate() throws RemoteException;

     

    void ejbPassivate() throws RemoteException;

    }

    The methods have the following semantics.

    setSessionContext() sets a session context. The session context interface provides methods to access runtime properties of the context in which a session runs. Details about the session and EJB contexts are given later in the chapter when we explain the deployment of an enterprise bean. This method is typically implemented by storing the session context in a private variable of the session bean implementation class. The variable must be declared not-transient to retain its value of de-activation/re-activation cycles.

    ejbRemove() notifies a session object that it is about to be removed. Whenever the container removes a session bean (for example, because a client invoked a remove operation on the remote or home interface), it calls this operation on the bean implementation.

    ejbActivate() notifies a session object that it has been activated.

    ejbPassivate() notifies a session object that it is about to be deactivated.

    The activation and deactivation notifications allow a sophisticated bean implementation to manage resources, which they may control.

    Optional Session Synchronization Interface

    The interface SessionSynchronization provides methods for session beans to get notified in the event of transaction synchronization. For example, implementing this interface allows a bean to synchronize cached data with the database within an ongoing transaction.

    package javax.ejb;

     

    public interface SessionSynchronization {

     

    void afterBegin() throws RemoteException;

     

    void beforeCompletion() throws RemoteException;

     

    void afterCompletion(boolean completionStatus) throws RemoteException;

     

    }

    The three methods are notifications from the container whenever a specific step in a transaction is completed.

    afterBegin() notifies the session bean that a new transaction has begun. The session bean is already in a transaction and any work that is executed is within the scope of this transaction.

    beforeCompletion() notifies the session bean that a client has completed work on the current transaction, but the resources involved have not yet been committed. The bean should now update the database with its cached values if there are any. If necessary, the session bean can force a rollback of the current transaction by invoking the method setRollBackOnly() on its session context.

    afterCompletion() notifies the session bean that the current transaction has been completed. The parameter completionStatus indicates the outcome of the transaction. The value true means committed; false means rollback.

    Session Bean Implementation

    A session bean implementation must implement:

  • The SessionBean interface

  • Optionally, the SessionSynchronization interface

  • Methods that correspond to the ones defined in the home interface

  • Methods defined in the remote interface

  • We have already explained the typical implementations of the methods of the SessionBean interface. See Figure 5.9.

    Figure 5.9  Relationships of a session bean implementation.

    The home interface defines one or more create methods. For each of these methods we have to declare and implement a corresponding create method. The naming convention for the session bean’s create methods corresponds to the one for the home interface. The create methods are called ejbCreate(). The parameters must match those defined in the home interface’s corresponding create methods. This includes the exceptions. The return value is, however, void (and not remote interface specified in the home interface). The pattern for ejbCreate() method is

    public void ejbCreate( <zero or more parameters> )

    throws RemoteException {

    // implementation

    }

    Finally, we have to implement methods corresponding to the ones defined in the remote interface. Their signatures must exactly match those of the methods defined in the remote interface. The type safety is ensured by the container. There is no explicit"implements" relationship between the remote interface and the EJB implementation class. The container usually checks type safety at install time. Appropriate development tools for EJB should ensure the type safety at development time.

    The constructor of the bean should not do anything; in fact, you can omit the constructor. All of the initialization of the bean is done in the ejbCreate() methods.

    Finally, we revisit the example from Chapter 1.

    package vogel.transaction.chapter1.ejb;

     

    import java.rmi.RemoteException;

     

    public class AtmBean implements SessionBean, Serializable{

     

    private SessionContext sessionContext;

     

    // application specific methods

     

    public void transfer(

    String sourceAccountId, String targetAccountId, float amount )

    throws RemoteException, InsufficientFundsException {

    //get the accounts

    ...

    // now that I got the accounts I make the transfer

    sourceAccount.debit( amount );

    targetAccount.credit( amount );

    return;

    }

    ATMBean has no constructor and we have omitted some parts of the implementation of the transfer method. In the remainder of the code we provide a trivial implementation of an ebjCreate() method and the methods defined in the SessionBean interface.

    // implement methods defined in SessionBean

     

    public void ejbCreate() throws RemoteException {

     

    System.out.println("ATM: create");

     

    }

     

    public void setSessionContext( SessionContext sessionContext ) {

    System.out.println("ATM: set session context");

    this.sessionContext = sessionContext;

    }

     

    public void ejbRemove() {

    System.out.println("ATM: remove");

    }

     

    public void ejbActivate() {

    System.out.println("ATM: activate");

    }

     

    public void ejbPassivate() {

    System.out.println("ATM: passivate");

    }

    Entity Beans

    A entity bean implementation must implement the entity bean interface and comply with a number of rules and naming conventions that define the relationship of this class to the remote and the home interface.

    Life Cycle of an Entity Bean

    The entity bean interface defines methods, similar to the ones in the session bean interface, which an entity bean must implement. To understand the meaning of the methods we must look at the life cycle of an entity bean, as shown in Figure 5.10.

    Figure 5.10  Life cycle of an entity bean.

    An instance of an entity bean is in one of the following three states:

    Nonexistent.  The instance does not exist.

    Pooled.  The instance exists but it is not associated with a particular EJB object entity; that is, there is no specific data associated with the instance.

    Ready.  The instance is associated with a particular EJB object entity; that is, there is specific data associated with the instance.

    An instance of an entity bean is created by the container. The container sets the context of the instance by invoking setEntityContext() on the entity bean. The instance is now in the pooled state. All the instances in the pool are equal since they are not associated with any data. When and how many instances in a pool are created is up to the container implementation.

    When a client invokes a finder method, the corresponding ejbFind() method is executed on an arbitrary object in the pooled state.

    An instance moves from the pooled to the ready state when the container selects this instance to service a client’s request on an entity object with no such instance in the ready state and in the proper transaction context. Then the container initializes the instance with the appropriate identity by invoking ejbCreate() and ejbPostCreate() on the instance. This is caused by a client invoking a create method on the home interface. An alternative way to move an instance from the pooled to the ready state is by ejbActivate(), which happens when an already existing object gets activated.

    An entity object is moved back to the pooled state by deactivating it. This means that the instance is decoupled from the data represented by the entity. This happens when the transaction is completed or when the entity bean is removed; the method ejbPassivate() or ejbRemove() is invoked on the entity bean, respectively. When an unassociated instance is removed from the pool the method unsetEntityContext() is invoked on it.

    When the instance is in the ready state, it is associated with a specific entity object. Clients can invoke the application-specific methods on the entity bean and the bean loads and stores its data as appropriate using the ejbLoad() and ejbStore() methods.

    Entity Bean Interface

    The session bean interface is defined as shown next.

    package javax.ejb;

     

    public interface EntityBean extends EnterpriseBean {

    void setEntityContext(EntityContext entityContext) throws RemoteException;

     

    void unsetEntityContext() throws RemoteException;

     

    void ejbRemove() throws RemoteException, RemoveException;

     

    void ejbActivate() throws RemoteException;

     

    void ejbPassivate() throws RemoteException;

     

    void ejbLoad() throws RemoteException;

     

    void ejbStore() throws RemoteException;

    }

    The methods have the following semantics.

    setEntityContext() sets an entity context. The entity context interface provides methods to access properties of the runtime context in which an entity bean runs. Details about the entity and EJB contexts are given later in the chapter when we explain the deployment of an enterprise bean. This method is typically implemented by storing the session context in a private variable of the session bean implementation class.

    unsetEntityContext() is called by the container before it terminates the life of the current instance of the entity bean. The bean can free resources that have been allocated during the setEntityContext() call.

    ejbRemove() removes the database entry or entries associated with this particular entity bean.

    ejbActivate() notifies an entity bean that it has been activated.

    ejbPassivate() notifies an entity bean that it is about to be deactivated.

    ejbLoad()refreshes the data the entity object represents from the database.

    ejbStore()stores the data the entity object represents in the database.

    Entity Bean Implementation

    An entity bean implementation must implement:

  • The EntityBean interface

  • Methods that correspond to the ones defined in the home interface

  • Methods that correspond to the ones defined in the remote interface

  • The amount of programming an enterprise bean provider has to do depends on the persistence policy, which is defined in the deployment descriptor. Persistence is the protocol or mechanism used to transfer the state of an entity bean to and from an underlying database. Note that the entity bean and the database may be connected via a legacy application.

    The specification identifies two approaches to implement persistence:

    Bean-managed persistence.  The entity bean implementation is responsible for implementing the persistence. The bean provider writes the code to access the underlying database or application. These calls are placed in the methods ejbCreate(), ejbFind…(), ejbRemove(), ejbLoad(), and ejbStore().

    Container-managed persistence.  The container is responsible for implementing the persistence. Instead of the bean provider implementing the database access code, the container is responsible for generating the appropriate code and its execution. The fields of the entity bean, which are managed by the container, must be specified in the deployment descriptor.

    The obvious advantage of container-managed persistence is that the bean provider is freed from the task of writing database access code. That, however, requires sophisticated tools provided by the container. In many cases these tools imply an object relational mapping.

    The example from Chapter 1 uses bean-managed persistence. We point out throughout the example which parts could have been omitted when using container-managed persistence.

    The class AccountBean implements the interface EntityBean. We declare two variables for the entity context and the account balance; that is, the state of the bean. Note that you have to declare state variables, which are container-managed, as public. We don’t declare a constructor. We also have a convenience function to obtain the primary key, the account identifier, from the entity context.

    package vogel.transaction.chapter1.ejb;

     

    import javax.ejb.*;

    import java.sql.*;

    import java.rmi.RemoteException;

     

    public class AccountBean

    implements EntityBean {

     

    private EntityContext entityContext;

    public float balance;

     

    private String accountId() {

    return (String) entityContext.getPrimaryKey();

    }

    The implementation of the application-specific methods, credit() and debit(), is straightforward: We just change the value of the state variable balance.

    public void credit( float amount )

    throws RemoteException {

     

    balance = balance + amount;

    return;

    }

     

    public void debit( float amount )

    throws RemoteException, InsufficientFundsException {

     

    if( balance >= amount )

    balance = balance - amount;

    else

    throw new InsufficientFundsException();

    return;

    }

    Now we implement the create and find methods corresponding to the ones defined in the home interface. For a container-managed implementation we would have trivial implementation, we only have to initial the state variables.

    For the bean-managed implementation we have to supply the database access code. We use JDBC in this example. But other APIs, for example, to object databases or to legacy applications, can be used. The ejbCreate() method we implement with an SQL insert, the ejbFindByPrimaryKey() method with an SQL select.

    public String ejbCreate( String accountId )

    throws RemoteException, CreateException {

     

    balance = 0;

    try {

    Statement statement = getStatement();

    ResultSet resultSet = statement.executeQuery(

    "insert into accounts values( '" + accountId + "', 0.0 )" );

    statement.close();

    }

    catch( Exception e ) {

    throw new RemoteException( e.toString() );

    }

    return accountId;

    }

     

    public void ejbPostCreate( String accountId ) {

    return ;

    }

     

    public String ejbFindByPrimaryKey( String accountId )

    throws RemoteException, FinderException {

     

    try {

    Statement statement = getStatement();

    ResultSet resultSet = statement.executeQuery(

    "select balance from accounts where id = '" + accountId + "'" );

    if( resultSet.next() ) {

    balance = resultSet.getFloat(1);

    ...

    return accountId;

    }

    Finally, we implement the methods defined in EntityBean interface. Setting and unsetting the entity context is straightforward. The implementation of the ejbRemove() method is provided by an SQL delete. We don’t add code to the activation and passivation of the entity bean.

    public void setEntityContext( EntityContext entityContext )

    throws RemoteException {

     

    this.entityContext = entityContext;

    }

     

    public void unsetEntityContext() throws RemoteException {

    entityContext = null;

    }

     

    public void ejbRemove() throws RemoteException {

    try {

    Statement statement = getStatement();

    ResultSet resultSet = statement.executeQuery(

    "delete from accounts where id = '" + accountId() + "'" );

    statement.close();

    }

    catch( Exception e ) {

     

    throw new RemoteException( e.toString() );

    }

    return;

    }

     

    public void ejbActivate() throws RemoteException {}

     

    public void ejbPassivate() throws RemoteException {}

    The ejbCreate(), ejbRemove(), ejbFind(), ejbLoad(), and ejbStore() methods are the biggest difference between container-managed and bean-managed implementation. For the container-managed case, we don’t have to do anything; in the bean-managed case, we have to make the database calls. For example, we implement the ejbLoad() method with a SQL select and the ejbStore() method with a SQL update. We have also implemented a little helper method to obtain a SQL statement.

    public void ejbLoad()

    throws RemoteException {

     

    try {

    Statement statement = getStatement();

    ResultSet resultSet = statement.executeQuery(

    "select balance from accounts where id = '" +

    accountId() + "'" );

    if( resultSet.next() ) {

    balance = resultSet.getFloat(1);

    ...

    }

    }

     

    public void ejbStore()

    throws RemoteException {

    try {

    Statement statement = getStatement();

    ResultSet resultSet = statement.executeQuery(

    "update accounts set balance = " + balance +

    " where id = '" + accountId() + "'");

    statement.close();

    }

    catch( Exception e ) {

    throw new RemoteException( e.toString() );

    }

    }

     

    private Statement getStatement() throws RemoteException {

    ...

    }

    }

    Furthermore, there are a number of rules and conventions to be observed:

    Concurrent access to entity beans.  The synchronization between concurrent invocations is managed by the container and is not the concern of the entity bean provider. The container typically uses one of the following strategies: database synchronization, or container synchronization. In the first case, the container provides multiple instances of the same entity bean and leaves the synchronization up to the database access calls in the ejbCreate(), ejbRemove(), ejbLoad(), and ejbStore() methods. In the second case, the container creates only one instance of the entity bean, which acquires an exclusive lock on the database. The concurrent invocations are serialized by the container.

    Reentrant entity beans.  By default, entity beans are not reentrant. When a call within the same transaction context arrives at the entity bean, the exception java.rmi.RemoteException is thrown. An entity bean can be declared reentrant in the deployment descriptor; however, special care needs to be taken in this case. The critical issue is that a container can generally not distinguish between a (loopback) call within the same transaction and a concurrent invocation (in the same transaction context) on that same entity bean. The second one is illegal and when the entity bean is marked reentrant it becomes the programmer’s responsibility to ensure this rule.

    EJB Deployment

    EJB deployer is responsible for taking an enterprise bean and deploying it in a certain context. The context determines the policies for executing the bean. These policies determine, for example, the transactional behavior or the access control of an enterprise bean.

    EJB deployer would typically use wizard-like tools, provided by the container, to set the deployment descriptor for enterprise beans. The EJB specification version 1.0 defines serialized Java objects of the type javax.ejb.deployment.SessionDescriptor or javax.ejb
    .deployment.EntityDescriptor, depending on the type of the enterprise bean. The subsequent versions of the EJB specification prescribe XML for the definition of deployment descriptors. For both reasons, the change of the specification and the fact that a deployer uses tools, we omit the syntactical representation of the deployment descriptor. Instead, we focus on the content of the deployment information.

    A deployment descriptor keeps information about the following:

  • Transaction policies govern the transactional behavior of a bean.

  • Access control policies govern the access to an enterprise bean.

  • JNDI names set the name under which the home interface of the enterprise is registered.

  • Type information defines the types, that is the name of the classes, for the home and remote interfaces, the primary key class (entity beans only), and the implementation class.

  • Properties for enterprise beans with container-managed persistence provide the information required by the container to manage the persistence of a bean.

  • Transaction Polices

    Transaction policies cover two aspects: the transaction scope and the isolation levels.

    Transaction Scope

    The EJB specification defines the values for the transactional scope:

    TX_NOT_SUPPORTED.  The enterprise bean does not support a global transaction.

    TX_SUPPORTS.  The enterprise bean supports a global transaction. If a caller makes an invocation in a transactional context, the container executes the invocation in the caller’s transactional. If a caller has no association with a transaction, the container executes the invocation without a transaction.

    TX_MANDATORY.  An invocation on the enterprise bean requires a transactional context. If a caller makes an invocation in a transactional context, the container executes the invocation in the caller’s transactional. If a caller has no association with a transaction, the container throws the exception javax.jta.TransactionRequiredException.

    TX_REQUIRED.  The enterprise bean requires a global transaction for the execution of an invocation. If a caller makes an invocation in a transactional context, the container executes the invocation in the caller’s transactional. If a caller has no association with a transaction, the container creates a new transaction and executes the invocation in with this transaction.

    TX_REQUIRED_NEW.  The enterprise bean requires a new global transaction and executes the invocation with this transaction.

    TX_BEAN_MANAGED.  The transactional behavior is managed by the enterprise bean implementation using the javax.transaction.CurrentTransaction.

    Transaction isolation levels are originally defined in the ANSI SQL specification. The concept has been adopted by the ODBC and JDBC standards and found its way in the EJB specification. Isolation level refers to the degree to which multiple interleaved transactions are prevented from interfering with each other in a multi-user database system. Ideally, one would like to have serializable transactions. That means that the interleaved execution of any set of concurrent transactions produces the same effect as a serial execution of the same transactions. There are three specific ways in which the serializability of a transaction may be violated.

    Dirty Read.  Transaction t1 modifies a row. Transaction t2 then reads the row. Now t1 performs a rollback and t2 has seen a row that never really existed.

    Non-repeatable Read.  Transaction t1 retrieves a row. Then transaction t2 updates this row and t1 retrieves the same row again. Transaction t1 has now retrieved the same row twice and has seen two different values for it.

    Phantoms.  Transaction t1 reads a set of rows that satisfy certain search conditions. Then transaction t2 inserts one or more rows that satisfy the same search condition. If transaction t1 repeats the read, it will see rows that did not exist previously. These rows are called phantoms.

    The transaction isolation levels are defined based on the above defined permitted violations.

    TRANSACTION_READ_COMMITTED.  Does not allow dirty reads but allows the other two violations.

    TRANSACTION_READ_UNCOMMITTED.  Allows all three violations.

    TRANSACTION_REPEATABLE_READ.  Allows phantoms but not the other two violations.

    TRANSACTION_SERIALIZABLE.  Does not allow any of the three violations.

    Access Control

    Access control is based on identities. There are three values you can set for enterprise bean defining with which identity it runs. These are:

    CLIENT_IDENTITY.  Runs the enterprise with the identity provided by the caller.

    SYSTEM_IDENTITY.  Runs the enterprise with a predefined system identity.

    SPECIFIED_IDENTITY.  Runs the enterprise with the identity specified in the deployment descriptor.

    The deployment descriptor allows you to specify an access control entry. It can be defined for individual methods or for all methods of the enterprise bean. An access control entry associates a set of identities or roles with a set of methods, meaning that only the specified clients with the specified identities or roles can invoke those methods.

    Note that the access control is type-based and not instance-based. That means you cannot formulate and enforce access control policies such as"only the creator of a session can access the session," or"only the portfolio owner and the financial consultant can access the portfolio."

    Naming

    For each enterprise bean you must define a name under which its home interface is registered with JNDI. JNDI is a way to locate enterprise beans. The name is specified using the syntax for JNDI names.

    Typing

    For each enterprise bean you must define a name of the classes for the home and the remote interface and for the bean implementation class. For entity beans you provide the name of the primary key class.

    Container-Managed Persistence

    To enable container-managed persistence, you must specify the fields, which are managed by the container.

    Application Assembling

    The task of an application assembler is to combine one or more enterprise beans with some additional components (servlets, applets, scripts, etc.). The result of the assembly process can be a complete application or another, more complex enterprise bean consisting of several enterprise beans. The EJB specification does not define much detail on the bean assembling. Generally, the client, which can be an application-level client or just another enterprise bean, has to do the following things:

    Locate the bean’s home interface.  The EJB specification defines the JNDI as the API to locate home interfaces.

    Obtain an EJB object.  Create a session bean, or create or find an entity bean.

    Invoke the EJB object.  Invoking methods on the EJB object’s remote interface.

    Locating the Home Interface

    The EJB specification defines JNDI as the API for locating home interfaces. JNDI is intended to be implemented on top of different services. Examples include the CORBA’s Naming Service, LDAP/X.500, flat file, and proprietary directory services. Figure 5.11 illustrates the different implementation choices. Typically, the EJB server provider selects a particular implementation of JNDI.

    Figure 5.11  JNDI and sample implementation.

    From the client’s point of view, the selected technology doesn’t matter. Client just needs to obtain an initial context and resolve the name to a home interface as shown in the following sample code. The initialization of the initial naming context factory is EJB container/server specific.

    AtmHome atmHome = null;

    try {

    Hashtable env = new Hashtable();

    env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY,

    "com.inprise.ejb.jndi.Context");

    javax.naming.Context root =
    new javax.naming.InitialContext(env);

    atmHome = (AtmHome) root.lookup("Atm");

    }

    catch( Exception ex ) {

    System.err.println(

    "Could not get home interface for ATM EJBs" + ex );

    }

    The context’s lookup() method returns an object of type java.lang.Object, which we have to cast to the expected type (for example, to the AtmHome interface).

    Obtaining the Remote Interface

    Now that we have obtained the home interface of an enterprise bean we can get a reference to the enterprise bean’s remote interface. We use the home’s create or finder methods. Exactly which method we call depends on the type of the enterprise bean and the methods the enterprise bean provider has defined in the home interface.

    Session Beans

    A client obtains a session bean by calling one of the create methods on the home interface. The default create method has no parameters; for example:

    Atm atm = atmHome.create();

    Stateless session beans have only create methods with no arguments. Stateful session beans can have a number of create methods. The additional parameters of these methods are used to initialize the session.

    Entity Beans

    A client obtains an entity typically through a find operation. The default find method is

    findByPrimaryKey( <key type> primaryKey )

    The key type can be any Java class, which implements Serializable. The primary key class is set in the deployment description. For example, we can obtain an account entity bean by using an account identifier of the type AccountPK.class, which contains a string or integer which is the account number.

    AccountPK accountPK = new AccountPK("1234-56-789");

    Account source = accountHome.findByPrimaryKey( accountPK );

    Again, the bean provider can define additional find methods to be used by a client. A client can also create entity beans using the home interface. However, note the different life spans of session and entity beans. While a session bean is typically only valid for a client’s session, an entity bean exists as long as its data is present in a database.

    Invoking Methods

    The client can now invoke methods on the EJB as defined in the remote interface. For example, we invoke the transfer method on the ATM bean.

    // transfer some money from savings to checking

    atm.transfer( "savings", "checking", 100f );

     

    // cleaning up

    atm.remove();

    }

    catch( Exception ex ) {

    ...

    }

    The invocation of the remove() method is specific to session beans. A well-behaved client should always call the remove() method once it is finished with the session object. If the client doesn’t do so, due to badly written code or due to a crash of the client program, the container will remove the object after a certain time. The timeout value is a deployment property. However, a client can also keep a handle to the session for future reference.

    Clients of entity beans don’t have to deal with this problem as entity beans are only associated with a client for the duration of a transaction and the container is in charge of their life cycles, including the activation and deactivation.

    CORBA and Enterprise JavaBeans

    There are a number of aspects to the relationship between CORBA and Enterprise JavaBeans. Three important ones are the implementation of an EJB container/server with an ORB, the integration of legacy systems into an EJB middle tier, and the access of enterprise beans from non-Java components, specifically clients. The EJB specification is currently only concerned with the third aspect.

    CORBA is a very suitable and natural platform on which to implement an EJB infrastructure. CORBA addresses all of the concerns of the EJB specification with the CORBA Core specification or the CORBA Services:

    Support for distribution.  CORBA Core and CORBA Naming Service

    Support for transactions.  CORBA Object Transaction Service

    Support for security.  CORBA Security Specification, including IIOP-over-SSL

    Additionally, the CORBA allows the integration of non-Java components into an application. These components can be legacy systems and applications and different kinds of clients. Back-ends can be easily integrated using OTS and any programming language for which an IDL mapping exists. That, however, requires an EJB container, which provides OTS and IIOP APIs as we explained earlier in the chapter.

    The EJB specification is concerned with the accessibility of enterprise beans from non-Java clients and provides an Enterprise JavaBean to CORBA mapping. The goals of the EJB/CORBA mapping are

  • Interoperability between clients written in any CORBA-supported programming language and enterprise beans running on a CORBA-based EJB server.

  • Enabling client programs to mix and match calls to CORBA objects and enterprise beans within the same transaction.

  • Supporting distributed transactions involving multiple enterprise beans running on CORBA-based EJB servers provided by different vendors.

  • The mapping is based on the Java-to-IDL mapping. The specification has the following parts: mapping of distribution-related aspects, the mapping of naming conventions, the mapping of transactions, and the mapping of security. We explain each of these aspects in the following sections. Since the mapping uses new IDL features introduced by the OMG’s Object-by-Value specification, interoperability with other programming languages requires CORBA 2.3-compliant ORBs.

    Mapping for Distribution

    An enterprise bean has two interfaces that are remotely accessible: the remote interface and the home interface. Applying the Java/IDL mapping to these interfaces results in corresponding IDL specifications. The base classes defined in the EJB specification are mapped to IDL in the same manner.

    We explain generation and use of IDL interfaces to enterprise with the ATM session bean introduced in Chapter 1. By applying the Java/IDL mapping to the home and the remote interface, we get the following IDL interface.

    module vogel {

    module transaction {

    module chapter1 {

    module ejb {

     

    valuetype InsufficientFundsException : ::java::lang::Exception {};

     

    exception InsufficientFundsEx {

    ::vogel::transaction::chapter1::ejb::InsufficientFundsException value;

    };

     

    interface Atm : ::javax::ejb::EJBObject{

     

    void transfer (in string arg0, in string arg1, in float arg2)

    raises (::vogel::transaction::chapter1::ejb::InsufficientFundsEx);

    };

     

    interface AtmHome : ::javax::ejb::EJBHome {

     

    ::vogel::transaction::chapter1::ejb::Atm create ()

    raises (::javax::ejb::CreateEx);

    };

    };};};};

    Mapping for Naming

    A CORBA-based EJB runtime environment that wants to enable any CORBA clients to access enterprise beans must use the CORBA Naming Service for publishing and resolving the home interfaces of the enterprise beans. The runtime can use the CORBA Naming Service directly or indirectly via JNDI and its standard mapping to the CORBA Naming Service.

    JNDI names have a string representation of the following form"directory1/directory2/…/directoryN/objectName". The CORBA Naming Service defines names as a sequence of name components.

    typedef string Istring;

     

    struct NameComponent {

    Istring id;

    Istring kind;

    };

     

    typedef sequence<NameComponent> Name;

    Each "/" separated name of a JNDI string name is mapped to a name component; the leftmost component is the first entry in the CORBA Naming Service name

    A JNDI string name is relative to some naming context, which we call the JNDI root context. The JNDI root context corresponds to a CORBA Naming Service initial context. CORBA Naming Service names are relative to the CORBA initial context.

    A CORBA program obtains an initial CORBA Naming Service naming context by calling resolve_initial_references("NameService") on the ORB (pseudo) object. The CORBA Naming Service does not prescribe a rooted graph for organizing naming context and, hence, the notion of a root context does not apply. Which context is returned by resolve_initial_references() depends on the initialization of the ORB.

    For example, a C++ Client could locate the home interface to our ATMSession bean, which has been registered with a JNDI string name "vogel/transaction/chapter1/corbaEjb/atm". First we obtain initial naming context.

    Object_ptr obj = orb->resolve_initial_refernces("NameService");

    NamingContext initialNamingContext= NamingContext.narrow( obj );

    if( current == NULL ) {

    cerr << "Couldn’t initial naming context" << endl;

    exit( 1 );

    }

    Then we create a CORBA Naming Service name and initialize it according to the mapping explained previously.

    Name name = new Name( 1 );

    name[0].id = "atm";

    name[0].kind = "";

    Now we resolve the name on the initial naming context. We assume that we have initialized so that we have context of the naming domain of the enterprise bean. We narrow the resulting CORBA object to the expected type and make sure that the narrow was successful.

    Object_ptr obj = initialNamingContext->resolve( name );

    ATMSessionHome_ptr atmSessionHome = ATMSessionHome.narrow( obj );

    if( atmSessionHome == NULL ) {

    cerr << "Couldn’t narrow to ATMSessionHome" << endl;

    exit( 1 );

    }

    Mapping for Transaction

    A CORBA-based EJB runtime environment that wants to enable any CORBA client to participate in a transaction involving enterprise beans must use the CORBA Object Transaction Service for transaction control.

    When an enterprise bean is deployed it can be installed with different transaction policies. The policy is defined in the enterprise bean’s control descriptor. If the policy is TX_NOT_SUPPORTED, the enterprise does not support transactions, and we don’t have to worry about the mapping of transactions to CORBA.

    If the transaction policy is set to a different value, the enterprise bean must be instructed to interoperate with the CORBA Object Transaction Service. The following rules have been defined for transactional enterprise beans: A CORBA client invokes an enterprise through stubs generated from the IDL interfaces for the enterprise bean’s remote and home interface. If the client is involved in a transaction, it uses the interfaces provided by CORBA Object Transaction Service. Details on the explicit transaction management are explained later in the chapter. For example, a C++ Client could invoke the ATMSession bean defined and located in the previous example.

    try {

    ...

    // obtain transaction current

    Object_ptr obj = orb->resolve_initial_refernces("Current");

    Current current = Current.narrow( obj );

    if( current == NULL ) {

    cerr << "Couldn’t resolve current" << endl;

    exit( 1 );

    }

     

    // execute transaction

    try {

    current->begin();

    atmSession->transfer("checking", "saving", 100.00 );
    current->commit( 0 );

    } catch( ... ) {

    current->rollback();

    }

    }

    catch( ... ) {

    ...

    }

    Mapping for Security

    Security aspects of the EJB specification are mainly focused on controlling the access to enterprise beans, as explained earlier in the chapter. CORBA defines a number of ways to define the identities, including the following cases:

    Plain IIOP.  CORBA’s principal interface was deprecated in early 1998. The principal interface was intended for determining the identity of a client. However, the authors of the CORBA security services decided to choose a different approach.

    The GIOP specification contains a component called service context, which is an array of an/value pair. The identifier is a CORBA long and the value is a sequence of octet. Among other purposes, entries in the service context can be used to identify a caller.

    Secure IIOP.  The CORBA security specification defines an opaque data type for the identity. The real type of the identity is determined by the chosen security mechanism; for example, GSS Kerberos, SPKM, or CSI-ECMA.

    IIOP over SSL.  SSL uses X.509 certificates to identify servers and, optionally, clients. When a server requests a client certificate, the server can use the certificate as a client identity.

  • Cover

    ISBN 0-471-31972-4
    368 pages
    May, 1999


    Wiley Computer Publishing
    Timely. Practical. Reliable.

    [Home] [Contents] [Chapter] [Code] [Updates] [Links] [Authors]