Introducing the EJB Programming Model
Now that you understand a little bit about the different types of EJBs, you are ready to start examining the EJB programming model. In fact, there are two distinctly different programming models for EJBs—one for session beans and entity beans, and another one for MDBs. We'll begin by looking at the way in which session and entity beans are developed and used, and then take a look at how the MDB approach differs from that base.
First, let's remember that EJBs are components. Each EJB is composed of a number of different classes—some provided by you the developer, and some provided by the EJB container. An example of this is how session and entity EJBs use the factory idiom for creating objects.
Since an EJB is a component, you can't simply use the new operator in Java to create on. The code that creates the EJB may not be running in the same JVM as the actual EJB, and, beyond that, the EJB container may want to pool EJB objects and reuse them to reduce the overhead of object creation. Instead, an EJB programmer must create a Java interface, called a home interface, which defines the ways in which the EJB will be created. The EJB factories that implement these interfaces (whose implementation is provided by the container) are called EJB homes.
So how, then, does a client obtain an EJB home? The client cannot use the new operator, since then she would simply be back in the same position we were in earlier. Clients locate EJB homes through a standard naming service that supports the JNDI API. JNDI is simple to use (like the RMI naming service) but it supports many of the advanced features of the CORBA naming service (like support for directory-structured names).
When you deploy a session or an entity bean, you give it a unique JNDI name; clients can then look the implementation of the home up through that unique name.
Once an EJB client obtains a home and uses it to look up or create and EJB, what does it receive in return? EJBs take the RMI approach of only requiring that the programmer define a simple Java interface that declares a remote object's external face to the rest of the world. In EJB terminology, this is called the remote interface, and it declares the externally accessible methods the remote object will implement. What the client receives, then, is another class provided by the container that implements this interface. This object acts as a proxy to the actual EJB implementation class, which is the final piece of this EJB that the developer is required to implement and provide to the container within the EJB-JAR file.
By applying the factory and proxy patterns in this way, the EJB specification avoids some of the problems that plagued CORBA and RMI. Since remote and home are Java interfaces, we avoid the need to program in both IDL and Java as in CORBA. Since EJB deployment automatically registers EJB homes in the JNDI namespace, we avoid the bootstrapping problem of RMI, since RMI required the developer to manually insert distributed objects into the RMI registry.
As we said earlier, starting in EJB 2.0 there are two ways to define homes and proxies for your EJBs, depending on whether or not the client knows it will be deployed within the same JVM as the EJB. In addition to declaring a home interface and a remote interface, EJB providers can declare a local home interface and a local interface. If the EJB client and the EJB are in the same JVM, then the client can choose to look up the local home rather than the remote home from the JNDI provider. The client will receive an object that implements the local interface from any of the local home's factory methods. In most other respects, using the local interface is the same as using a remote interface. We'll discuss what this means to the design of your EJB programs in the next section.
Finally, we come to the programming model of MDBs. This model is significantly simpler than the programming model for entity or session beans, since MDBs do not have clients that invoke specific methods on those beans. A MDB responds to any messages that are sent to the JMS destination that it monitors, regardless of how that message arrived at that destination. So, this simplifies the interface of the MDB down to a single method—onMessage(Message aMsg). All MDBs implement this same interface, although each will respond differently to the message that is received. Likewise, since there is no need to look up an MDB from JNDI, there is no home or local home interface for the MDB.