Primary Services




Primary Services

Many value-added services are available for distributed applications. This book looks at eight value-added services that are called the primary services because they are required to complete the Enterprise JavaBeans platform. The primary services include concurrency, transactions, persistence, distributed objects, asynchronous messaging, a timer service, naming, and security. EJB servers automatically manage all of the primary services. This capability relieves application developers from the task of mastering these complicated services. Instead, developers can focus on defining the business logic that describes the system and can leave the system-level concerns to the EJB server. The following sections describe each primary service and explain how they are supported by EJB.

Concurrency

Concurrency is important to all the bean types, but it has different meanings for each type.

Concurrency with session and entity beans

Session beans do not support concurrent access. This limitation makes sense if you consider the nature of stateful and stateless session beans. A stateful bean is an extension of one client and serves only that client. It doesn't make sense to make stateful beans concurrent if they are used only by the clients that created them. Stateless session beans don't need to be concurrent because they don't maintain state that needs to be shared. The scope of the operations performed by a stateless bean is limited to the scope of each method invocation. Because neither stateful nor stateless session beans represent shared data, there is no need for concurrency.

Because EJB servers handle concurrency, a bean's methods do not have to be made thread-safe. In fact, the EJB specification prohibits the use of the synchronized keyword. Prohibiting the use of the thread synchronization primitives prevents developers from thinking that they control synchronization and enhances the performance of bean instances at runtime. In addition, the EJB specification explicitly prohibits beans from creating their own threads. In other words, as a bean developer, you cannot create a thread within a bean. The EJB container has to maintain complete control over the bean in order to properly manage concurrency, transactions, and persistence. Allowing the bean developer to create arbitrary threads would compromise the container's ability to track what the bean is doing and would make it impossible for the container to manage the primary services.

Entity beans represent data that is shared and may be accessed concurrently. Entity beans are shared components. In Titan Cruises' EJB system, for example, there are three ships: the Paradise, the Utopia, and the Valhalla. At any given moment, the Ship entity bean that represents the Utopia might be accessed by hundreds of clients. To make concurrent access to entity beans possible, the persistence provider needs to protect the data represented by the shared bean while allowing many clients to access the logical entity bean simultaneously.

In the Java Persistence specification, the persistence container protects shared entity data by making a copy of the entity bean instance on a per-transaction basis. Since each transaction has a snapshot of the entity, concurrent multithreaded access is possible. So how does the container protect against stale reads or different transactions trying to update the same entity at the same time? Optimistic concurrency using version fields is one way. Another way is setting the JDBC isolation level to SERIALIZED. Vendor implementations may also provide ways to obtain row locks directly in the database. All of this is discussed in great detail in Chapter 16.

Concurrency with message-driven beans

In message-driven beans, concurrency refers to the processing of more than one message at a time. If message-driven beans could process only a single message at a time, they would be practically useless in a real-world application because they couldn't handle heavy message loads. As Figure illustrates, if three messages are delivered to a specific destination from three different clients at the same time, three instances of a single JMS-MDB that subscribes or listens to that destination can be used to process the messages simultaneously.

Concurrent processing with message-driven beans


Message-driven beans that implement APIs other than JMS benefit from the same concurrency controls as JMS-MDBs. Message-driven beans of all kinds are pooled and used to process incoming messages concurrently so that hundreds, possibly thousands, of messages can be handled simultaneously.[*]

[*] In reality, it's very difficult to process anything simultaneously without multiple processors, but conceptually this statement is true. Multiple threads in the same VM or multiple VMs on the same processor (computer chip) imitate simultaneous processing.

Transactions

A transaction is a unit of work or a set of tasks that are executed together. Transactions are atomic; in other words, all the tasks in a transaction must be completed together for the transaction to be considered a success. In the previous chapter, we used the TravelAgent bean to describe how a session bean controls the interactions of other beans. Here is the bookPassage( ) method described in Chapter 2:

public Reservation bookPassage(CreditCardDO card,double price)
    throws IncompleteConversationalState {
     if (customer == null ||cruise == null ||cabin == null){
         throw new IncompleteConversationalState( );
     }
     try {
          Reservation reservation =
             new Reservation(customer,cruise,cabin,price,new Date( ));
          entityManager.persist(reservation);
          process.byCredit(customer,card,price);
          return reservation;
     } catch(Exception e) {
         throw new EJBException(e);
     }
}

The bookPassage( ) method consists of two tasks that must be completed together: the creation of a new Reservation entity and the processing of the payment. When the TravelAgent EJB is used to book a passenger, the charges to the passenger's credit card and the creation of the reservation must both be successful. It would be inappropriate for the ProcessPayment EJB to charge the customer's credit card if the creation of a new Reservation entity fails. Likewise, you can't make a reservation if the customer's credit card is not charged. An EJB server monitors the transaction to ensure that all the tasks are completed successfully.

Transactions are managed automatically, so, as a bean developer, you don't need to use any APIs to manage a bean's involvement in a transaction. Simply declaring the transactional attributes at deployment time tells the EJB server how to manage the bean at runtime. EJB does provide a mechanism that allows beans to manage transactions explicitly, if necessary. Setting the transactional attributes during deployment is discussed in Chapter 16, as are explicit management of transactions and other transactional topics.

Persistence

Entity beans represent the behavior and data associated with real-world people, places, or things. Unlike session and message-driven beans, entity beans are persistent, which means that the state of an entity is saved in a database. Persistence allows entities to be durable so that both their behavior and their data can be accessed at any time without concern that the information will be lost because of a system failure.

Java Persistence

Persistence in EJB 3.0 has been totally revamped and rearchitected within the Java Persistence specification. While the EJB 2.1 model was component-based persistence, the Java Persistence model is a plain Java-based model (often called POJO Persistence). Entities can be created outside the scope of the EJB container. They are allocated as any other Java object using the new( ) operator. An entity can be attached to container management, or detached. Bean instances are attached to persistent storage through the EntityManager service. The EntityManager service provides methods to create, find, query, remove, and update entity beans. When a bean instance is attached, the container manages the persistent state of the bean and automatically synchronizes the bean with its data source.

An interesting thing about the Java Persistence model is that bean instances can be detached from the EJB container. Bean instances are usually detached from the EJB container when a transaction completes. These detached instances can be sent around the network to remote clients or even saved to disk. Their state can be modified and then reattached to the EJB container by using the EntityManager.merge( ) method. When bean instances are reattached, any changes made to the bean are synchronized with persistent storage. This new persistence model allows EJB developers to throw away the old Data Transfer Object pattern, greatly simplifying application architecture. We'll talk more about this in Chapter 5.

Object-to-relational persistence

Object-to-relational (O/R) persistence involves mapping an entity bean's state to relational database tables and columns. Since relational databases are used in 99 percent of database applications, the EJB 3.0 Expert Group realized that it is better to focus on object-to-relational mapping than to try to create a persistence architecture that is one-size-fits-all. As a result, the Java Persistence specification provides rich relational database mapping with advanced features such as inheritance, multitable mappings, versioning, and expanded EJBQL support. Since O/R mapping is mandated by the specification now, this makes EJB applications much more portable between vendors, as there will be a lot less vendor-specific metadata.

Let's give a simple overview of O/R mapping. In Titan's system, Cabin models the concept of a ship's cabin. Cabin defines three fields: name, deckLevel , and id. The definition of Cabin looks like this:

@Entity
@Table 
(name="CABIN")
public class Cabin {
    private int id;
    private String name;
    private int deckLevel; 


    @Column 
(name="NAME")
    public String getName( ) { return name; }
    public void setName(String str) { name = str; }

    @Column(name="DECK_LEVEL") 

    public int getDeckLevel( ) { return deckLevel;
    public void setDeckLevel(int level) { deckLevel = level; }

    @Id 

    @Column(name="ID")
    public int getId( ) { return id; }
    public void setId(int id) { this.id = id; }

}

In this example, the accessor methods represent the entity bean's container-managed fields. With O/R database mapping, the fields of an entity bean correspond to columns in a relational database. Metadata about the O/R mapping is defined in annotations on the access methods (@Column and @Id) and on the bean class (@Table). Cabin's deckLevel field, for example, maps to the column labeled DECK_LEVEL in a table called CABIN in Titan's relational database. Figure shows a graphical depiction of this type of mapping.

O/R mapping of entity beans


Once a bean's fields are mapped to the relational database, the container takes over the responsibility of keeping the state of an entity bean instance consistent with the corresponding tables in the database. This process is called synchronizing the state of the bean instance. In the case of Cabin, bean instances map one to one to rows in the CABIN table of the relational database. When a change is made to a Cabin entity, it is written to the appropriate row in the database. Sometimes, bean types map to more than one table. These are more complicated mappings, often requiring an SQL join and multiple updates, and are discussed in later chapters.

In addition, Java Persistence defines entity bean relationship fields, which allow entity beans to have one-to-one, one-to-many, and many-to-many relationships with other beans. Entity beans can maintain collections of other entity beans or single references. The Java Persistence model is covered in Chapters 510.

Distributed Objects

When we discuss the component interfaces and other EJB interfaces and classes used on the client, we are talking about the client's view of the EJB system. The EJB client view doesn't include session bean class instances, the EJB container, instance swapping, or any of the other implementation specifics of session beans. As far as a remote client is concerned, a bean is defined by its remote interface or endpoint interface.[*] Everything else is invisible, including the mechanism used to support distributed objects. As long as the EJB server supports the EJB client view, any distributed object protocol can be used. EJB 3.0 requires that every EJB server support Java RMI-IIOP, but it doesn't limit the protocols an EJB server can support to just Java RMI-IIOP (the Java RMI API using the CORBA IIOP protocol). It also requires support for SOAP 1.2 via the JAX-RPC API.

[*] This doesn't include entity beans, though, as entity bean class instances may be detached from container management and sent to a remote client as long as these entity classes implement java.io.Serializable

Regardless of the protocol, the server must support Java clients using the Java EJB client API, which means that the protocol must map to the Java RMI-IIOP or the JAX-RPC programming model. Figure illustrates the Java language EJB API supported by different distributed object protocols.

Java EJB client view supported by various protocols


EJB also allows servers to support access to beans by clients written in languages other than Java. An example of this capability is the EJB-to-CORBA mapping defined by Sun.[*] This document describes the CORBA Interface Definition Language (IDL) that can be used to access enterprise beans from CORBA clients. A CORBA client can be written in any language, including C++, Smalltalk, Ada, and even COBOL. The mapping also includes details about supporting the Java EJB client view, as well as details about mapping the CORBA naming system to EJB servers and distributed transactions across CORBA objects and beans. Another example is the EJB-to-SOAP mapping based on JAX-RPC. It allows SOAP client applications written in languages such as Visual Basic .NET, C#, and Perl to access stateless session beans. Figure illustrates the possibilities for accessing an EJB server from different distributed object clients.

[*] Sun Microsystems' Enterprise JavaBeans™ to CORBA Mapping, Version 1.1, by Sanjeev Krishnan. Copyright© 1999 by Sun Microsystems

EJB accessed from different distributed clients


Asynchronous Enterprise Messaging

Prior to EJB 2.0, asynchronous enterprise messaging was not considered a primary service because it wasn't necessary in order to have a complete EJB platform. However, with the introduction of message-driven beans, asynchronous enterprise messaging with JMS has become so important that it has been elevated to the status of a primary service.

Support for enterprise messaging requires that the EJB container reliably route messages from JMS clients to JMS-MDBs. Reliable routing involves more than the simple delivery semantics associated with email or even the JMS API. With enterprise messaging, messages must be reliably delivered, which means that a failure while delivering the message may require the JMS provider to attempt redelivery.[] What's more, enterprise messages may be persistent, which means they are stored to disk or to a database until they can be properly delivered to their intended clients. Persistent messages also must survive system failures; if the EJB server crashes, these messages must still be available for delivery when the server comes back up. Most importantly, enterprise messaging is transactional. That means if a JMS-MDB fails while processing a message, that failure will abort the transaction and will force the EJB container to redeliver the message to another message-driven bean instance.

[] Most EJB vendors will place a limit on the number of times a message can be redelivered. If redelivery is attempted too many times, the message might be placed in a "dead message" repository, where it can be reviewed by an administrator.

In addition, message-driven beans, stateless session beans, and entity beans can also send JMS messages. Sending messages can be as important to Enterprise JavaBeans as delivery of messages to JMS-MDBsupport for both facilities tends to go hand in hand.

EJB Timer Service

The EJB Timer Service can be used to schedule notifications that are sent to enterprise beans at specific times. Timers are useful in many different applications. For example, a banking system may set timers on mortgage accounts to check for past-due payments. A stock-trading system might allow timers to be set on "buy limit orders." A medical claims system may set timers for automatic fraud audits of individuals' medical records. Timers can also be used in applications like self-auditing systems and batch processing.

Timers can be set on entity, stateless session, and message-driven beans. With session and entity beans, the bean sets the timers itself. For example, when a mortgage loan is created, the entity bean that represents the loan might set a past-due timer when the loan is created and reset the timer whenever a payment is made. Some EJB container systems may support message-driven bean timers, which are configured at deployment time and perform batch processing at regular intervals. The Timer Service is covered in detail in Chapter 13.

Naming

All naming services do essentially the same thing: they provide clients with a mechanism for locating distributed objects or resources. To accomplish this, a naming service must provide two things: object binding and a lookup API. Object binding is the association of a distributed object with a natural language name or identifier. The travelAgentRemote object, for example, might be bound to the name "TravelAgentRemote" or "agent." A binding is really a pointer or an index to a specific distributed object. A lookup API provides the client with an interface to the naming system. Simply put, lookup APIs allow clients to connect to a distributed service and request a remote reference to a specific object.

Enterprise JavaBeans mandates the use of JNDI as a lookup API on Java clients. JNDI supports just about any kind of naming and directory service. Although JNDI can become extraordinarily complex, the way it's used in Java EE applications is usually fairly simple. Java client applications can use JNDI to initiate a connection to an EJB server and to locate a specific EJB. The following code shows how the JNDI API might be used to locate and obtain a reference to the travelAgentRemote EJB:

javax.naming.Context jndiContext = new javax.naming.InitialContext( );
 

Object ref = jndiContext.lookup("TravelAgentRemote");
TravelAgentRemote agent = (TravelAgentRemote)
    PortableRemoteObject.narrow(ref, TravelAgentRemote.class);

Reservation res = agent.bookPassage(...);

The properties passed into the constructor of InitialContext tell the JNDI API where to find the EJB server and what JNDI service provider (driver) to load. The Context.lookup( ) method tells the JNDI service provider the name of the object to return from the EJB server. In this case, we are looking for the remote interface to the TravelAgent EJB. Once we have the TravelAgent EJB's remote interface, we can begin to invoke methods on the service to do things like book reservations.

There are many different kinds of directory and naming services; EJB vendors can choose the one that best meets their needs, but all vendors must support the CORBA naming service in addition to any other directory services they choose to support.

Security

Enterprise JavaBeans servers can support as many as three kinds of security:


Authentication

Simply put, authentication validates the identity of the user. The most common kind of authentication is a simple login screen that requires a username and a password. Once users have successfully passed through the authentication system, they are free to use the system. Authentication can also be based on secure ID cards, swipe cards, security certificates, and other forms of identification. While authentication is the primary safeguard against unauthorized access to a system, it is fairly crude because it doesn't police an authorized user's access to resources within the system.


Authorization

Authorization (a.k.a. access control) applies security policies that regulate what a specific user can and cannot do. Access control ensures that users access only those resources for which they have been given permission. Access control can police a user's access to subsystems, data, and business objects, or it can monitor more general behavior. Certain users, for example, may be allowed to update information while others are allowed only to view the data.


Secure communication

Communication channels between a client and a server are frequently the focus of security concerns. A channel of communication can be secured by encrypting the communication between the client and the server. When communication is secured by encryption, the messages passed are encoded so that they cannot be read or manipulated by unauthorized individuals. This normally involves the exchange of cryptographic keys between the client and the server. The keys allow the receiver of the message to decode the message and read it.

We'll talk more about security in Chapter 17.

Primary Services and Interoperability

Interoperability is a vital part of EJB. The specification includes the required support for Java RMI-IIOP for remote method invocation and provides for transaction, naming, and security interoperability. EJB also requires support for JAX-RPC, which itself requires support for SOAP 1.1 and WSDL 1.1; these are the standards of the web services industry.

IIOP

EJB requires vendors to provide an implementation of Java RMI that uses the CORBA 2.3.1 IIOP protocol. The goal of this requirement is that Java EE application servers will be able to interoperate so that Java EE components (enterprise beans, applications, servlets, and JSPs) in one Java EE server can access enterprise beans in a different Java EE server. The Java RMI-IIOP specification standardizes the transfer of parameters, return values, and exceptions, as well as the mapping of interfaces and value objects to the CORBA IDL.

Vendors may support protocols other than Java RMI-IIOP, as long as the semantics of the RMI interfaces adhere to the types allowed in RMI-IIOP. This constraint ensures that a client's view of EJB is consistent, regardless of the protocol used in remote invocations.

Transaction interoperability between containers for two-phase commits is an optional but important feature of EJB. It ensures that transactions started by a Java EE web component propagate to enterprise beans in other containers. The EJB specifications detail how two-phase commits are handled across EJB containers as well as how transactional containers interact with nontransactional containers.

EJB also addresses the need for an interoperable naming service for looking up enterprise beans. It specifies CORBA CosNaming as the interoperable naming service, defining how the service must implement the IDL interfaces of beans in the CosNaming module and how EJB clients use the service over IIOP.

EJB provides security interoperability by specifying how EJB containers establish trust relationships and how containers exchange security credentials when Java EE components access enterprise beans across containers. EJB containers are required to support the Secure Sockets Layer (SSL 3.0) protocol and the related IETF-standard Transport Layer Security (TLS 1.0) protocol for secure connections between clients and enterprise beans.

While IIOP has been around for a long time and offers interoperability in a number of areas, the truth is it hasn't been very successful. There are a variety of reasons why IIOP has not been the silver bullet it was intended to be, but perhaps the biggest reason is complexity. Although IIOP is platform-independent, it's not trivial for vendors to implement. In addition, there appear to be numerous gaps in the IIOP and other CORBA protocols, which cause interoperability problems when actually deployed in a production environment. It's rare to hear of real-world systems that have successfully deployed interoperating EJB systems based on IIOP. The solution the industry seems to have latched on to is web services, which depend on SOAP and WSDL as the bases for interoperability.

SOAP and WSDL

SOAP (Simple Object Access Protocol) is the primary protocol used by web services today. It's based on XML and can be used for both RPC- and document (asynchronous)-style messaging. The fact that SOAP is based on XML means that it's fairly easy to support. Any platform (operating system, programming language, software application, etc.) that can create HTTP network connections and parse XML can handle the SOAP protocol. This is why SOAP has gained widespread acceptance in a short period of time. More than 70 SOAP toolkits (code libraries) are available today for just about every modern programming environment, including Java, .NET, JavaScript, C, C++, Visual Basic, Delphi, Perl, Python, Ruby, Smalltalk, and others.

WSDL (Web Service Description Language) is the IDL of the web services. A WSDL document is an XML file that describes what web services a company supports, as well as the protocols, message formats, and network addresses of those web services. WSDL documents are highly structured, so they can be used to autogenerate RPC stubs and other software interfaces for communicating with web services. Although WSDL documents are open enough to describe any type of service, they are typically used to describe web services that use the SOAP protocol.

WSDL and SOAP are normally used in combination. They form the building blocks for other interoperability standards covering security, transaction, orchestration, enterprise messaging, and a cornucopia of other topics. There is a lot of overlap among different groups that are developing infrastructure protocols based on SOAP and WSDL, and, as a result, there are a lot of conflicting and immature standards. SOAP and WSDL have a lot of promise, but it's still too soon to say whether web services will solve the interoperability problems that have plagued enterprise computing since the beginning. It's likely that SOAP, WSDL, and the infrastructure protocols based on these standards will go farther than IIOP, DCOM, and other predecessors, but they won't be a silver bullet. Web services are covered in more detail in Chapters 18 and 19.