EJB internals

Although we’ve talked about the role of the container and the concept of managed services, we haven’t explained how most containers go about providing managed services. The secret to understanding these and the other EJB services is knowing how the container provides them. Without going into too much detail, we’ll discuss EJB objects—which perform the magic of providing the service—and then examine the EJB context—which a bean can use to access runtime environment and use container services.

EJB behind the scenes

EJB centers on the idea of managed objects. As we saw in the previous topics, EJB 3 beans are just annotated POJOs themselves. When a client invokes an EJB method using the bean interface, it doesn’t work directly on the bean instance. The container makes beans "special" by acting as a proxy between the client and the actual bean instance. This enables the container to provide EJB services to the client on behalf of the bean instance.

NOTE For each bean instance, the container automatically generates a proxy called an EJB object. The EJB object has access to all the functionality of the container, including the JNDI registry, security, transaction management, thread pools, session management, and pretty much anything else that is necessary to provide EJB services. The EJB object is aware of the bean configuration and what services the POJO is supposed to provide.


Since all requests to the EJB instance are passed through the EJB object proxy, the EJB object can "insert" container services to client requests as needed, including managing all aspects of the bean lifecycle. Figure 5.1 is a typical representation of this technique.

As you’ve seen in the previous topics, the beauty of this technique is that all the service details are completely transparent to bean clients and even to bean developers. In fact, a container implementation is free to implement the services in the most effective way possible and at the same time provide vendor-specific feature and performance enhancements. This is fundamentally all there is to the "magic" parts of EJB. For session beans, the client interacts with the EJB object through the business interface. For MDBs, however, the EJB object or message endpoint sits between the message provider and the bean instance.

Let’s now take a look at how EJBs access the container environment in which the EJB object itself resides.

The "magic" of EJB. The container-generated EJB object receives all EJB client requests as the proxy, and reads configuration and inserts container services as required before forwarding client requests to the bean instance.

Figure 5.1 The "magic" of EJB. The container-generated EJB object receives all EJB client requests as the proxy, and reads configuration and inserts container services as required before forwarding client requests to the bean instance.

EJB context: accessing the runtime environment

EJB components are generally meant to be agnostic of the container. This means that in the ideal case, EJB components should merely hold business logic and never access the container or use container services directly. As you’ll recall, services like transaction management, security, dependency injection, and so forth are meant to be "overlaid" on the bean through configuration.

However, in the real world, it is sometimes necessary for the bean to explicitly use container services in code. These are the situations the EJB context is designed to handle. The javax.ejb.EJBContext interface is essentially your backdoor into the mystic world of the container. In this section, we define EJBContext, explain its use, and show you how to use dependency injection to retrieve EJBContext.

Defining the EJBContext Interface

As you can see in listing 5.1, the EJBContext interface allows direct programmatic access to services such as transaction and security, which are typically specified through configuration and completely managed by the container.

Listing 5.1 javax.ejb.EJBContext interface

Listing 5.1 javax.ejb.EJBContext interface

Let’s look briefly at what each of these methods do (table 5.1). We’ll save a detailed analysis for later, when we discuss the services that each of the methods is related to. For now, you should note the array of services offered through the EJB context as well as the method patterns.

Table 5.1 You can use javax.ejb.EJBContext to access runtime services.

Methods

Description

tmp24-151

These methods are useful when using in bean-managed security. We discuss these two methods further in chapter 6 when we discuss programmatic security.

tmp24-152

These methods are used to obtain the bean’s "remote home" and "local home" interfaces, respectively. Both are optional for EJB 3 and are hardly used beyond legacy EJB 2.1 beans. We won’t discuss these methods beyond this basic introduction. They are mainly provided for backward compatibility.

tmp24-153

These methods are used for EJB transaction management in the case of container-managed transactions. We discuss container-managed transactions in greater detail in chapter 6.

tmp24-154

This method is used for EJB transaction management in the case of bean-managed transactions. We discuss bean-managed transactions in greater detail in chapter 6.

tmp24-155

This method is used to get access to the EJB timer service. We discuss EJB timers later in this chapter.

tmp24-156

This method is used to get references to objects stored in the JNDI registry. With the introduction of DI in EJB 3, direct JNDI lookup has been rendered largely unnecessary. However, there are some edge cases that DI cannot handle, or perhaps DI is simply not available. This method proves handy in such circumstances. We discuss this topic later in this section.

Both session and message-driven beans have their own subclasses of the javax. ejb.EJBContext interface. As shown in figure 5.2, the session bean-specific subclass is javax.ejb.SessionContext, and the MDB-specific subclass is javax.ejb. MessageDrivenContext.

The EJB context interface has a subclass for each session and message-driven bean type.

Figure 5.2 The EJB context interface has a subclass for each session and message-driven bean type.

Each subclass is designed to suit the particular runtime environment of each bean type. As a result, they either add methods to the superclass or invalidate methods not suited for the bean type. For example, it doesn’t make sense to call the isCallerlnRole method from an MDB because the MDB is not invoked directly by a user.

Using EJBContext

As we discussed earlier, you can gain access to several container services such as transaction or security by using EJBContext. Interestingly, you can access EJBContext through DI. For example, a SessionContext could be injected into a bean as follows:

tmp24158_thumb

In this code snippet, the container detects the @Resource annotation on the context variable and figures out that the bean wants an instance of its session context. The SessionContext adds a number of methods specific to the session bean environment, including getBusinessObject, getEJBLocalObject, getEJBObject, getlnvokedBusinesslnterface, and getMessageContext. All of these are fairly advanced methods that are rarely used. Note that the getEJBLocalObject and getEJBObject methods are meant for EJB 2 beans and will generate exceptions if used with EJB 3 beans. We won’t discuss these methods further and will leave them for you to explore on your own.

MessageDrivenContext adds no methods specific to MDB. Rather, it throws exceptions if the isCallerlnRole, getEJBHome, or getEJBLocalHome methods are called since they make no sense in a messaging-based environment (recall that a message-driven bean has no business interface and is never invoked directly by the client). Much like a session context, a MessageDrivenContext can be injected as follows:

tmp24159_thumb

NOTE It is illegal to inject a MessageDrivenContext into a session bean or a SessionContext into an MDB.

This is about as much time as we need to spend on the EJB context right now. Rest assured that you’ll see more of it in topic 6. In the meantime, let’s turn our attention back to a vital part of EJB 3—dependency injection. We provided a brief overview of DI in topic 2 and have been seeing EJB DI in action in the last few topics. We just saw an intriguing use case in injecting EJB contexts. In reality, EJB DI is a like a Swiss army knife: it is an all-in-one tool that can be used in unexpected ways. Let’s take a look at some of these advanced uses next.

Next post:

Previous post: