Modeling real-life objects and concepts is one of the first skills a programmer must develop. As such, we’ve become fairly adept at implementing object-oriented axioms such as reusability and extensibility on a daily basis. When we focus these principles on business logic, we end up with a set of business objects that encapsulate the rules of the road.
Starting with the 3.0 version of the Specification, EJB imposes no API coupling or restrictions upon the classes that will define our business objects. Commonly known as POJO (Plain Old Java Object)* development, this means that an application developer is under no obligation to extend, implement, or have any references tying the application to EJB. Now we can create class hierarchies however we see fit, and reuse our objects in some non-EJB environment (perhaps for quick testing outside of the Container).
Because a POJO class is just like any other class, it does not become an EJB until it’s:
3. Accessed via the Container
This is an important distinction. EJBs become such only in the context of the EJB Container.
The Container, in turn, is responsible for equipping POJOs with EJB Services as well as exposing their behavior via one of three personalities. We call these personalities component types, and while implementing their semantics is beyond scope for an application developer, it’s important to know how, by contract, they’ll behave.
We’ll use the example of a fictitious casino to showcase where each component type might be applied.
Server-Side Component Types
Server-side component types reside exclusively on the server, and the client must interact with them via some indirection. There are two major server-side component types: session beans, which expose a view for the client to invoke upon, and message-driven beans, which act as event listeners.
If EJB is a grammar, session beans are the verbs. They take action, and they frequently contain business methods. Because of EJB’s distributed nature, underlying bean instances that carry out the invocation live on the server and are accessed by way of a simple view the client may request of the EJB Container. This means that the client does not access the EJB directly, which allows the Container to perform all sorts of magic before a request finally hits the target method. It’s this separation that allows for the client to be completely unaware of the location of the server, concurrency policies, or queuing of requests to manage resources. As far as the client is concerned, it’s operating directly upon an EJB. In truth, the client is invoking upon a proxy reference that will delegate the request along to the Container and return the appropriate response (see Figure 2-1).
Figure 2-1. Client invoking upon a proxy object, responsible for delegating the call along to the EJB Container
Ultimately, it’s the bean instances created and managed by the Container that the service client requests.
Stateless session beans (SLSBs)
Stateless session beans are useful for functions in which state does not need to be carried from invocation to invocation. A client cannot assume that subsequent requests will target any particular bean instance. In fact, the Container will often create and destroy instances however it feels will be most efficient (see Figure 2-2). How a Container chooses the target instance is left to the vendor’s discretion.
Figure 2-2. An SLSB Instance Selector picking an instance at random
Because there’s no rule linking an invocation to a particular target bean instance, these instances may be used interchangeably and shared by many clients. This allows the Container to hold a much smaller number of objects in service, hence keeping memory footprint down.
One caveat to beware: though a SLSB has stateless semantics, it’s backed by an instance of a class created by the application developer. Particular care must be employed to assure that any shared members (instance variables, for instance) are not leaked between invocations; this may lead to unpredictable behavior.
If we were to give our casino a game of roulette, SLSB would be a natural implementation choice. Roulette is a game with no memory—each spin operates independently from the last—so a function getSpinResult should return a random spot on the wheel.
Stateful session beans (SFSBs)
Stateful session beans differ from SLSBs in that every request upon a given proxy reference is guaranteed to ultimately invoke upon the same bean instance. This is to say, SFSB invocations share conversational state. Each SFSB proxy object has an isolated session context, so calls to one session will not affect another.
Stateful sessions, and their corresponding bean instances, are created sometime before the first invocation upon a proxy is made to its target instance (Figure 2-3). They live until the client invokes a method that the bean provider has marked as a remove event, or until the Container decides to evict the session (usually due to some timeout, though the spec leaves this out-of-scope and up to the vendor).
Figure 2-3. Stateful session bean creating and using the correct client instance, which lives inside the EJB Container, to carry out the invocation
In order to minimize the number of stateful sessions carried around in memory, the Container may passivate a SFSB bean instance. During passivation, the session’s state is flushed to some persistent storage such that it may be removed from RAM. If the session is needed again before it’s removed for good, the Container will activate it and bring the bean instance back into memory.
No casino is complete without a good game of poker, and we could build ours using SFSBs. Each game is played using a single deck, and we need to keep track of which cards have already been dealt—otherwise we risk giving the player next to us the impossible hand of five aces! If each table is scoped to its own stateful session, we could ensure that the integrity of the deck is intact.
We’ll dive into SFSBs. Singleton beans
Sometimes we don’t need any more than one backing instance for our business objects. EJB 3.1 therefore introduces a new session component type, the singleton bean. Because all requests upon a singleton are destined for the same bean instance, the Container doesn’t have much work to do in choosing the target (Figure 2-4).
The singleton session bean may be marked to eagerly load when an application is deployed; therefore, it may be leveraged to fire application lifecycle events. This draws a relationship where deploying a singleton bean implicitly leads to the invocation of its lifecycle callbacks. We’ll put this to good use when we discuss singleton beans.
Dealers in a casino aren’t granted complete autonomy; they’ve got to clear a set of privileged tasks such as changing money, cashout, and large betting with the pit boss. The pit boss, in turn, is the sole authority over what’s permitted on his floor. If we model the boss as a singleton, all requests are passed along to the same source—one able to make informed, consistent decisions. In addition, at the start of the pit boss’s shift, he can make the rounds and do whatever startup tasks he deems necessary.
Figure 2-4. Conceptual diagram of a singleton session bean with only one backing bean instance
Message-Driven Beans (MDBs)
Asynchronous messaging is a paradigm in which two or more applications communicate via a message describing a business event. EJB 3.1 interacts with messaging systems via the Java Connector Architecture (JCA) 1.6 (http://jcp.org/en/jsr/detail?id=322), which acts as an abstraction layer that enables any system to be adapted as a valid sender. The message-driven bean, in turn, is a listener that consumes messages and may either handle them directly or delegate further processing to other EJB components. The asynchronous characteristic of this exchange means that a message sender is not waiting for a response, so no return to the caller is provided (Figure 2-5).
Figure 2-5. Asynchronous invocation of a message-driven bean, which acts as a listener for incoming events
One common provider of asynchronous messaging is the Java Message Service (JMS), and the EJB specification dictates that JMS is supported implicitly.^ If a message is sent to a JMS Topic or Queue, an MDB may be created to take action upon that event. By extension, any service with a valid JCA Resource Adapter may use MDB as an endpoint.
Like SLSBs, MDBs have no conversational state. Any instance may be used in servicing a message. In fact, the client has no view or knowledge of the MDB at all! Once the client sends a message, it’s out of scope to worry about what may be listening to the event fired.
After a full night of gambling, visitors to our casino are likely to need their cars back from the valet. We may provide our valet service via MDBs; once a ticket (message) is received, the valet should fetch the car while its owner continues on to grab a cup of coffee or visit the gift shop. The casino visitor will have to frequently check back to see whether his car has arrived.
While session beans are our verbs, entity beans are the nouns. Their aim is to express an object view of resources stored within a Relational Database Management System (RDBMS)—a process commonly known as object-relational mapping.
Like session beans, the entity type is modeled as a POJO, and becomes a managed object only when associated with a construct called the javax.persistence.EntityManager, a container-supplied service that tracks state changes and synchronizes with the database as necessary. A client who alters the state of an entity bean may expect any altered fields to be propagated to persistent storage. Frequently the EntityManager will cache both reads and writes to transparently streamline performance, and may enlist with the current transaction to flush state to persistent storage automatically upon invocation completion (Figure 2-6).
Figure 2-6. Using an EntityManager to map between POJO object state and a persistent relational database
Unlike session beans and MDBs, entity beans are not themselves a server-side component type. Instead, they are a view that may be detached from management and used just like any stateful object. When detached (disassociated from the EntityManager), there is no database association, but the object may later be re-enlisted with the EntityManager such that its state may again be synchronized. Just as session beans are EJBs only within the context of the Container, entity beans are managed only when registered with the EntityManager. In all other cases entity beans act as POJOs, making them extremely versatile.
Users familiar with EJB 2.x forms may be used to the former notion of Container Managed Persistence (CMP), which required dependence upon a verbose API. Although entity bean classes were once required to implement specific interfaces and their callback methods explicitly, these restrictions have been removed as of the 3.0 revision of the EJB Specification.
Entity beans are introduced in Part III.
The Java Persistence Model
The sister to the EJB 3.1 Specification is the Java Persistence API (JPA) 2.0, developed in JSR-317 (http://jcp.org/en/jsr/detail?id=317). EJBs may become equipped with the facilities defined by JPA, such that modifying the properties of a managed object will be reflected automatically in the backing database. In addition to support within EJB, JPA may be used in standalone Java Standard Edition (SE) environments.
Persistence is simply a higher-level abstraction above Java Database Connectivity (JDBC). By exposing the database as objects to the developer, backing rows may be queried, loaded, updated, or removed without explicitly having to go through a contracted API or language such as SQL. In older versions of EJB, persistence was part of the specification, but starting with EJB 3.0, it has been spun off on its own. The entity bean is EJB’s integration with JPA, and it is defined by enhancing a plain class definition with some additional persistence metadata.
The Model Isn’t Everything
The various EJB Component types allow stateful, stateless, asynchronous, and persistent logic to be easily modeled. Now it’s time to see how they’ll shine under the bright lights of Container services.