While server-side component types handle business logic and entities address state, the EJB Container can continue to make our jobs easier by providing a wide range of generic and configurable services. Enterprise applications generally handle a large number of concurrent users, and each request might need to be handled carefully so it does not violate the security or integrity of the application. Additionally, we shouldn’t waste our time wiring our modules together; the container can do this for us. Perhaps we have some other cross-cutting concern we’d like to model and apply on our own. For these requirements, EJB offers a range of container services.
Security addresses the need to authorize and authenticate users uniformly across the application. Not all requests should be given carte blanche access to the whole application, and this is EJB’s mechanism to declaratively or programmatically restrict access.
Injection allows our modules to communicate with one another without the explicit need to perform service lookups. We can also use injection to define dependency relationships between resources.
Transactions ensure that our application’s state maintains its integrity while under load from concurrent use. Although traditionally this is a very difficult paradigm to achieve manually, EJB provides us with a declarative syntax to guard our business logic methods and, by extension, associated resources such as the EntityManager.
Interceptors are a generic utility for defining your own application logic to be applied in a cross-cutting manner. This is a powerful way to promote code reuse, and it’s built into the platform.
The Timer Service allows the EJB container to fire time-based events into business logic methods. Instead of servicing a client request, we may instead set triggers to, for instance, process a batch job every hour.
Web Services address the need for interoperability with other platforms outside Enterprise Java.
Dependency Injection (DI)
A component-based approach to software design brings with it the complication of inter-module communication. Tightly coupling discrete units together violates module independence and separation of concerns, while using common lookup code leads to the maintenance of more plumbing. Martin Fowler details this problem in his paper “Inversion of Control Containers and the Dependency Injection Pattern,” which has spurred the development and success of many popular standalone DI containers.^
As EJB is a component-centric architecture, it provides a means to reference dependent modules in decoupled fashion. The end result is that you’ll adhere to a contract and let the container provide the implementation at deployment time.
In pseudocode, this looks like:
The fictitious @DependentModule annotation serves two purposes:
• Defines a dependency upon some service of type MailModule. UserModule may not deploy until this dependency is satisfied.
• Marks the instance member mail as a candidate for injection. The container will populate this field during deployment.
Assuming each Service is represented by one instance, dependency injection alone is a fine solution for a single-threaded application; only one client may be accessing a resource at a given time. However, this quickly becomes a problem in situations where a centralized server is fit to serve many simultaneous requests. Deadlocks, livelocks, and race conditions are some of the possible nightmares arising out of an environment in which threads may compete for shared resources. These are hard to anticipate, harder to debug, and are prone to first exposing themselves in production! Proper solutions lie outside the scope of this topic,t and for good reason: EJB allows the application developer to sidestep the problem entirely thanks to a series of concurrency policies.
That said, there are a series of effects upon performance to consider, so the specification allows for configuration in some cases. Otherwise, it’s important to be aware how each component type views concurrency concerns.
Because of the strict concurrency rules enforced by the Container, an intentional bottleneck is often introduced where a service instance may not be available for processing until some other request has completed. If the service was restricted to a singular instance, all subsequent requests would have to queue up until their turn was reached (see Figure 3-1).
Figure 3-1. Client requests queuing for service
Conversely, if the service was permitted to use any number of underlying instances, there would be no guard to say how many requests could be processed in tandem, and access across the physical machine could crawl to a halt as its resources were spread too thin (Figure 3-2).
Figure 3-2. Many invocations executing concurrently with no queuing policy
EJB addresses this problem through a technique called instance pooling, in which each module is allocated some number of instances with which to serve incoming requests (Figure 3-3). Many vendors provide configuration options that allow the deployer to allocate pool sizes appropriate to the work being performed, providing the compromise needed to achieve optimal throughput.
Figure 3-3. A hybrid approach using a pool
When a bean calls createTimer(), the operation is performed in the scope of the current transaction. If the transaction rolls back, the timer is undone and it’s not created (or, more precisely, it’s uncreated).
In most cases, the timeout callback method on beans should have a transaction attribute of RequiresNew. This ensures that the work performed by the callback method is in the scope of container-initiated transactions.
Most enterprise applications are designed to serve a large number of clients, and users are not necessarily equal in terms of their access rights. An administrator might require hooks into the configuration of the system, whereas unknown guests may be allowed a read-only view of data.
It’s bad practice, however, to hardcode users’ access directly into your application’s logic. We shouldn’t have to rebuild an EJB each time a new employee comes into the company or an existing one is promoted to a new position with greater privileges.
The Java EE and EJB specifications provide a core set of security services that application developers can integrate declaratively and programmatically. These include:
This is the process of validating the identity of a user who is trying to access a secured system. When authenticating, the application server verifies that the user actually exists in the system and has provided the correct credentials, such as a password.
Once a user is authenticated in a system, he will want to interact with the application. Authorization involves determining whether a user is allowed to execute a certain action. Authorization 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, whereas others are allowed only to view the data. For web applications, maybe only certain users are permitted to access certain URLs. For EJB applications, the user can be authorized on a per-method basis.
Although a small programmatic API is available for interacting with Java EE security services, users rarely have to write any code to secure their applications, because setting up security is usually a static, declarative process. Only session beans can be secured in EJB. This topic focuses on how to set up authentication and authorization for your session beans.
So far, we’ve dealt exclusively with client-initiated requests. While this may handle the bulk of an application’s requirements, it doesn’t account for scheduled jobs:
• A ticket purchasing system must release unclaimed tickets after some timeout of inactivity.
• An auction house must end auctions on time.
• A cellular provider should close and mail statements each month.
The EJB Timer Service may be leveraged to trigger these events and has been enhanced in the 3.1 specification with a natural-language expression syntax.
Naming and Object Stores
All naming services essentially do the same thing: they provide clients with a mechanism for locating distributed objects or resources. To accomplish this, a naming service must fulfill two requirements: object binding and a lookup API. Object binding is the association of a distributed object with a natural language name or identifier. A lookup API provides the client with an interface to the naming system; it simply allows us to connect with a distributed service and request a remote reference to a specific object.
Enterprise JavaBeans mandates the use of Java Naming and Directory Interface (JNDI; http://java.sun.com/products/jndi/) as a lookup API on Java clients. JNDI supports just about any kind of naming and directory service. Although it can become extraordinarily complex, the way JNDI is used in Java Enterprise Edition (EE) applications is usually fairly simple. Java client applications can use JNDI to initiate a connection to an EJB server and locate a specific EJB.
There are many different kinds of directory and naming services, and 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.
Naming is a subset of the resource management features offered by EJB.
Although it’s nice that the dependency injection facilities allow components within EJB to play nicely, we don’t live in a bubble. Our application may want to consume data from or provide services to other programs, perhaps written in different implementation languages. There are a variety of open standards that address this inter-process communication, and EJB leverages these.
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-WS, JAX-RPC, Web Services for Java EE, and Web Services Metadata for the Java Platform specifications (EJB 3.1 Specification, 2.6).
Some services require some initialization or cleanup to be used properly. For example, a file transfer module may want to open a connection to a remote server before processing requests to transfer files and should safely release all resources before being brought out of service.
For component types that have a lifecycle, EJB allows for callback notifications, which act as a hook for the bean provider to receive these events. In the case of our file transfer bean, this may look like:
Here we’ve annotated functions to open and close connections as callbacks; they’ll be invoked by the container as their corresponding lifecycle states are reached.
From the very start, we’ve been focusing on finding a proper home for all code in an application. Business logic is accessible from session or message-driven beans, domain nouns are in entities, and services such as security and transactions are handled as configurable aspects by the container. However, there might be cross-cutting concerns demanded by your unique requirements that are too specific to be handled by an open specification. For these cases, EJB 3.1 provides a generic interception framework in the form of the Interceptors 1.1 Specification.
Interceptors are objects that can interpose themselves on method calls or the lifecycle events of session and message-driven beans. They allow you to encapsulate common behavior that cuts across large parts of your application. This behavior is usually common code that you don’t want polluting your business logic. Where most of the changes to the EJB 3.x specifications were designed to make EJB easier to use for application developers, interceptors are an advanced feature that provide you another way to modularize your application or even extend your EJB container. This topic teaches you how to write an interceptor and shows you various real-world examples of where interceptors can be used.
As a key technology within the Java Enterprise Edition (JEE) 6 (http://jcp.org/en/jsr/detail?id=313), EJB aggregates many of the other platform frameworks and APIs:
• Java Transaction Service
• Java Persistence API
• Java Naming and Directory Interface (JNDI)
• Security Services
• Web Services
In most cases, the EJB metadata used to define this integration is a simplified view of the underlying services. This gives bean providers a set of powerful constructs right out of the box, without need for additional configuration.
EJB is also one of the target models recognized by the new Java Contexts and Dependency Injection specification (http://jcp.org/en/jsr/detail?id=299). This new kid on the block adds a unified binding to both Java Enterprise and Standard editions across many different component types.
Bringing It Together
Enough theory; up to this point, we’ve introduced topics only conceptually. In the next topic we’ll take off the gloves and ditch pseudocode for the real deal.