The Enterprise Bean Component




The Enterprise Bean Component

Enterprise JavaBeans server-side components come in two fundamentally different types: session beans and message-driven beans . Session beans are server-side components that can be accessed using a variety of distributed object protocols. Message-driven beans process messages asynchronously from systems like the JMS, legacy systems, and web services. All EJB servers must at least support a JMS-based message-driven bean, but they may also support other types of message-driven beans.

Session beans are extensions of the client application that manage processes or tasks. A Ship entity bean provides methods for doing things directly to a ship, but it doesn't say anything about the context under which those actions are taken. Booking passengers on the ship requires that we use a Ship entity, but it also requires a lot of things that have nothing to do with the ship itself: we'll need to know about passengers, ticket rates, schedules, and so on. A session bean is responsible for this kind of coordination. Session beans tend to manage particular kinds of activities, such as the act of making a reservation. They have a lot to do with the relationships between different entity beans. A TravelAgent session bean, for example, might use a Cruise, a Cabin, and a Customerall entity beansto make a reservation.

Similarly, message-driven beans coordinate tasks involving other session and entity beans. Message-driven beans and session beans differ primarily in how they are accessed. While a session bean provides a remote interface that defines which methods can be invoked, a message-driven bean subscribes to or listens for messages. It responds by processing the message and managing the actions that other beans take. For example, a ReservationProcessor message-driven bean would receive asynchronous messagesperhaps from a legacy reservation systemfrom which it would coordinate the interactions of the Cruise, Cabin, and Customer beans to make a reservation.

The activity that a session or message-driven bean represents is fundamentally transient: you start making a reservation, you do a bunch of work, and then it's finished. The session and message-driven beans do not represent things in the database. Obviously, session and message-driven beans have lots of side effects on the database; in the process of making a reservation, you might create a new Reservation by assigning a Customer to a particular Cabin on a particular Ship. All of these changes would be reflected in the database by actions on the respective entity beans. Session and message-driven beans like TravelAgent and ReservationProcessor, which are responsible for making a reservation on a cruise, can even access a database directly and perform reads, updates, and deletes to data. But there's no TravelAgent or ReservationProcessor record in the databaseonce the bean has made the reservation, it waits to process another.

What makes the distinction between the different types of beans difficult to understand is that it's extremely flexible. The relevant distinction for Enterprise JavaBeans and Java Persistence is that an entity bean has persistent state; session and message-driven beans model interactions but do not have a persistent state.

Classes and Interfaces

A good way to understand the design of enterprise beans is to look at how you'd go about implementing one. To implement session and message-driven enterprise beans, you need to define their component interfaces, and a bean class:


Remote interface

The remote interface defines a session bean's business methods, which can be accessed from applications outside the EJB container: the business methods a bean presents to the outside world to do its work. The remote interface is a plain Java interface. It is tagged with the @javax.ejb.Remote annotation to identify that it is a remote interface.


Local interface

The local interface defines a session bean's business methods that can be used by other beans in the same EJB container: the business methods a bean presents to other beans running in the same JVM. It allows beans to interact without the overhead of a distributed object protocol, which improves their performance. The local interface is a plain Java interface. It is tagged with the @javax.ejb.Local annotation to identify that it is a local interface.


Endpoint interface

The endpoint interface defines business methods that can be accessed from applications outside the EJB container via SOAP. The endpoint interface is based on Java API for XML-RPC (JAX-RPC) and is designed to adhere to the SOAP and WSDL standards. The endpoint interface is a plain Java interface that is annotated with the @javax.jws.WebService annotation.


Message interface

Message-driven beans implement the message interface, which defines the methods by which messaging systems, such as the JMS, can deliver messages to the bean.


Bean class

The session bean class contains business logic and must have at least one remote, local, or endpoint interface. It usually implements these interfaces, but it is not required to. A bean class may also have more than one interface of a given type. The EJB container usually determines whether a session bean is remote and/or local by the interfaces it implements. The session bean class must also be tagged with the @javax.ejb.Stateful or @javax.ejb.Stateless annotation so that the EJB container knows what session bean type it is.

A message-driven bean implements one or more message delivery methods (e.g., onMessage( )) defined in a message interface. The container calls these methods when a new message arrives. The message-driven bean class must also be tagged with the @javax.ejb.MessageDriven annotation. EJB 3.0 containers must support JMS-based message-driven beans, which implement the javax.jms.MessageListener interface. EJB also supports message-driven beans that process messages from other types of messaging systems with their own message interfaces.

Local interfaces provide a way for session beans in the same container to interact efficiently. Calls to methods in the local interface don't involve a distributed object protocol. A session bean isn't required to provide a local interface if it will only ever interact with remote or web service clients. Likewise, a session bean doesn't need to provide a remote or an endpoint interface if you know it will be called only by session beans in the same container. You can provide any combination of local, remote, and endpoint interfaces.

Clients of a session bean never interact with the session bean class directly (this includes clients that are themselves session beans). Instead, clients must always use the methods of the session bean's component interfaces to do their work. When they go through the component interfaces, the clients are actually interacting with proxies or stubs that are generated automatically by the container. Although local interfaces do not involve a distributed object protocol, they still represent a proxy or stub to the bean class. This is because, although no network is involved, the proxy or stub will still allow the container to monitor the interactions between the bean and its client, thus allowing the container to apply security and engage in transactions as appropriate.

It's important to note that message-driven beans don't support remote, local, or endpoint component interfaces, but they may become the clients of other session beans and interact with those beans through their component interfaces. The session beans with which the message-driven bean interacts may be located in the same container, in which case the message-driven bean uses their local component interfaces; or, they may be located in a different address space and EJB container, in which case the remote or endpoint component interfaces are used.

There are also many interactions between an enterprise bean and its container. (Many people use the terms container and server interchangeably, which is understandable because the difference between the terms isn't clearly defined.) The container is responsible for creating new instances of beans, making sure they are stored properly by the server, and so on. Tools provided by the container's vendor do a tremendous amount of work behind the scenes. At least one tool takes care of creating the mapping between entity beans and records in the database. Other tools generate code based on the component interfaces and the bean class itself. The generated code does things like create the bean, store it in the database, and so on.

Naming conventions

Before going on, let's establish some conventions. When we speak about an enterprise bean as a wholeits component interfaces, bean class, and so forthwe will call it by its common business name followed by the acronym EJB. For example, an enterprise bean that is developed to process credit card payments will be called the ProcessPayment EJB. Notice that we don't use a constant-width font for "ProcessPayment," because we are referring to all the parts of the bean (the component interfaces, bean class, etc.) as a whole, not just to one particular part, such as the remote interface or bean class. The term enterprise bean or bean denotes any kind of bean, including session and message-driven beans. Session bean denotes a session-type enterprise bean; message-driven bean denotes a message-driven-type enterprise bean. The acronym MDB is frequently used in place of the term message-driven bean.

We also use suffixes to distinguish between local, remote, and endpoint component interfaces. When we are talking about the remote interface of a TravelAgent session bean, we will combine the common business name with the word Remote. For example, the remote interface for the TravelAgent EJB is called the travelAgentRemote interface. The local interface for the TravelAgent EJB would be the TRavelAgentLocal interface. The endpoint interface for the TravelAgent EJB-based web service would be TRavelAgentWS (WS stands for web service). The bean class is always the common business name followed by the word Bean. For example, the TravelAgent EJB's bean class would be named travelAgentBean.

These naming conventions are used for clarity; they are not prescriptive or even recommended for use in production. Once you understand the differences between the component interfaces and the different types of beans, you can use any naming strategy you wish.

The remote interface

Having introduced the machinery, let's look at how to build a very simple stateless session bean with a remote component interface. In this section, we examine the Calculator EJB, a session bean that exposes basic calculator functions as a service. Let's start with its remote interface.

We'll define the remote interface for the Calculator bean using the CalculatorRemote interface, which defines arithmetic operations. Remote interfaces are denoted by the @javax.ejb.Remote annotation:

import javax.ejb.Remote;

@Remote
public interface CalculatorRemote {
    public int add(int x, int y);
    public int subtract(int x, int y);
}

You'll notice that even though this is the remote interface of the EJB, there is no reference to Java RMI interfaces or APIs. This is a big change in the EJB 3.0 specification compared to older versions. The EJB specification requires at least Java RMI-IIOP as an underlying network transport protocol, but all references to RMI have been removed to facilitate plugging in any other protocol that your container vendor wants to provide. Java RMI-IIOP will be discussed in more detail in the next chapter.

The bean class

Now let's look at an actual stateless session bean class. Here's the code for the CalculatorBean class; it's a sparse implementation, but it shows how the pieces fit together:

import javax.ejb.*;

@Stateless
public class CalculatorBean implements CalculatorRemote {
    public int add(int x, int y) {
        return x + y;
    }
    public int subtract(int x, int y) {
        return x - y;
    }
}

The CalculatorBean class is required to implement at least one remote or local interface and to be annotated with @javax.ejb.Stateless . Those familiar with earlier EJB specifications will notice that session beans do not have to implement an EJB-specific interface or any of the callback notifications. This is one of the ease-of-use mandates of the EJB 3.0 specification where EJBs must be as close to plain Java objects as possible. That's not to say the specification has removed callback notifications, but rather that they can be added on an as-needed basis. We'll discuss callback notifications in Chapter 11.

What about message-driven beans?

Message-driven beans also have a bean class that implements a message interface; they don't implement remote, local, or endpoint interfaces. This bean class is annotated using the @javax.ejb.MessageDriven annotation. The kind of message delivery methods implemented by the MDB depends on the type of messaging service it supports. For example, a JMS-based MDB, which all EJB containers must support, must implement the onMessage( ) method, which is called every time a new asynchronous JMS message is delivered.

Message-driven beans don't have a primary key, for the same reason that session beans don't. They are not persistent, so there is no need for a key to the database. Message-driven beans are covered in detail in Chapter 12.

Annotations, Deployment Descriptors, and JAR Files

The interfaces and classes we have discussed don't address how beans are managed at runtime. We didn't talk about how beans interact with security, transactions, naming, and other services common to distributed object systems. These types of primary services are handled automatically by the EJB container; but that begs the question, "How does the EJB container know how to handle security, transactions, and so on?" The EJB container gets this kind of runtime information from intuitive defaults, annotations, and/or XML deployment descriptors.

To simplify development of EJBs, the new EJB 3.0 specification defines a set of intuitive defaults so that developers do not have to add the syntactical sugar of an annotation or write an XML deployment descriptor. For instance, the default transaction property is REQUIRED. The default security semantics are UNCHECKED. These defaults allow the developer to focus on writing business logic instead of focusing on unneeded metadata.

When a default is not enough, you can use explicit Java annotations. Annotations allow EJB developers to specify metadata like security, transactions, and database mappings directly in the bean class file. Annotations alleviate some of the reliance on specific EJB tools because the metadata for EJB is expressed as annotations rather than just XML. Most integrated development environments (IDEs) support automatic code completion, and EJB annotations just become another element that an IDE can code-complete.

Annotations are by far the easiest way to define EJB metadata. Sometimes, though, you will want to override an annotation on a per-deployment basis. Furthermore, some in the Java community do not like annotations at all. To solve both of these issues, the EJB specification has the notion of an XML deployment descriptor. Deployment descriptors allow you to customize an EJB's runtime behavior without having to change the software itself and recompile anything. Deployment descriptors are also similar to the property sheets used in Visual Basic and PowerBuilder. Where property sheets allow us to describe the runtime attributes of visual widgets (background color, font size, etc.), deployment descriptors allow us to describe runtime attributes of server-side components (security, transactional context, etc.).

When a bean class and its interfaces have been defined, a deployment descriptor for the bean may be created and populated with data about the bean as an override or alternative to any annotations used. IDEs that support the development of Enterprise JavaBeans often allow developers to set up the deployment descriptors they need using visual utilities like property sheets. After the developer has set all of the bean's properties, the deployment descriptor is saved to a file. Once the deployment descriptor is completed and saved to a file, the bean can be packaged in a JAR file for deployment.

The choice between annotations and XML deployment descriptor comes down to personal taste. Some developers like to see EJB metadata embedded in the bean class and interface. They think an XML file is just too verbose. Annotations can also act like documentation. By looking at a class or interface source file, you know the exact semantics of what a particular EJB will be. On the other hand, others view this metadata as intrusive and want to code their business logic as plain Java, with no reference to EJB whatsoever. They also want to be able to change this metadata without modifying code. This could be really important if the EJB metadata needs to be different on a per-deployment basis. Since annotation metadata can be overridden partially or entirely by an XML deployment descriptor, there really is no need for this debate. Developers can rapidly prototype EJBs using annotations, and then, if needed, the metadata can be overridden within XML. The introductory examples in the early chapters of this book rely entirely on annotations to explain themselves. Chapter 11 will walk through how you can use XML as an alternative to annotations when defining session or message-driven beans.

JAR files are Zip files that package Java classes and other resources that are ready to be used in some type of application. JARs are used for packaging applets, Java applications, JavaBeans, web applications (servlets and JSPs), and Enterprise JavaBeans. A JAR file containing one or more enterprise beans includes the bean classes, component interfaces, and supporting classes for each bean. It also may contain a deployment descriptor if the bean developer has decided to use XML to define a bean's metadata. When a bean is deployed, the JAR file's location is given to the container's deployment tools.

When the container opens the JAR file, it looks for classes that are annotated as EJBs and/or reads the deployment descriptor (if one has been defined) to learn about the bean and how it should be managed at runtime. From the annotations and/or the deployment descriptor, the deployment tools know what kinds of beans are in the JAR file (session or message-driven), how they should be managed in transactions, who has access to the beans at runtime, and other information. The person deploying the bean can alter some of these settings, such as transactional and security access attributes, to customize the bean for a particular application.

The EJB Container

Session beans declare component interfaces that their clients use to access them. (Entity and message-driven beans are a very different kind of animal.) In EJB 3.0, clients outside the container system always use the enterprise bean's remote component interfaces. Clients outside the container system have the option of accessing stateless session beans as web services as well. Clients within the same Java EE system (i.e., enterprise beans, servlets, and JSPs) can use local component interfaces if they are running within the same virtual machine. This section explains how session bean component interfaces are connected to instances of the bean class at runtime.

Now that you have a basic understanding of some of an enterprise bean's parts (component interfaces, bean class, annotations, and deployment descriptor), it's time to talk more precisely about how these parts come together inside an EJB container system. Since the author of this book is a lead developer on the JBoss open source Java EE application server, you'll get some pretty good insight on how EJB containers are architected. Specifically, we'll talk about how JBoss' EJB container implements the component interface of a session bean so that clientseither applications outside the container or other co-located enterprise beanscan interact with and invoke methods on the bean class.

The three pieces you need in order to understand this architecture are the proxy stub, the container, and the bean instance itself. You will probably never deal with the internal architecture of your EJB container because the purpose of middleware is to alleviate these concerns so that you can focus on writing business logic. This practice is useful, though, because it represents a separation of responsibilities along areas of expertise. As an application developer, you are intimately familiar with how your business environment works and needs to be modeled, so you will focus on creating the applications and beans that describe your business. System-level developers, the people who write EJB servers, don't understand your business, but they do understand how to develop containers and support distributed objects. It makes sense for system-level developers to apply their skills to the mechanics of managing distributed objects but to leave the business logic to you, the application developer. Let's talk briefly about the proxy, the EJB container, and the bean instance so that you can get a general understanding of the internal architecture of EJB.

The proxy stub, EJB container, and bean instance

This chapter has said a lot about a bean's remote and local interfaces. When your business logic interacts with a session bean, it is not working directly with instances of the bean class; it is working through the bean's remote or local interface. When you invoke methods on the remote or local interface, the object instance you are using is something called a proxy stub. This proxy stub implements the remote or local interface of the session bean and is responsible for sending your session bean method invocation over the network to your remote EJB container or routing the request to an EJB container that is local in the JVM. The proxy stub can be generated by a precompiler, such as RMI's rmic. Or, as in the case of JBoss, it is dynamically generated at deployment time using the java.lang.reflect.Proxy facilities that come with the JDK.

The proxy stub routes the method invocation to the EJB container on the server (or in the server if it is a local interface). It is the EJB container's job to manage bean class instances as well as security and transaction demarcation. The EJB container has knowledge of the metadata defined as annotations on the bean class or as elements in the XML deployment descriptor. Based on this metadata, it will start a transaction and perform authentication and authorization tasks. It also is responsible for managing the life cycle of the bean instance and routing the request from the proxy to the real bean class instance.

After the EJB container has managed the life cycle of the bean instance, started any transactions, and performed its security checks, it routes the invocation to an actual bean instance.