As you learned in Chapter 2, Enterprise JavaBeans is a component model for component transaction monitors, the most advanced type of business application server available today. To effectively use Enterprise JavaBeans, you need to understand the EJB architecture, so this book includes two chapters on the subject. This chapter explores the core of EJB: how enterprise beans are distributed as business objects. Chapter 3 explores the services and resource management techniques supported by EJB.
To be truly versatile, the EJB component design had to be smart. For application developers, assembling enterprise beans is simple, requiring little or no expertise in the complex system-level issues that often plague three-tier development efforts. While EJB makes it easy for application developers, it also provides system developers (the people who write EJB servers) with a great deal of flexibility in how they support the EJB specification.
The similarities among different component transaction monitors (CTMs) allow the EJB abstraction to be a standard component model for all of them. Each vendor’s CTM is implemented differently, but they all support the same primary services and similar resource management techniques. The primary services and resource management techniques are covered in more detail in Chapter 3, but some of the infrastructure for supporting them is addressed in this chapter.
Enterprise JavaBeans server-side components come in two fundamentally different types: entity beans and session beans. A good rule of thumb is that entity beans model business concepts that can be expressed as nouns. For example, an entity bean might represent a customer, a piece of equipment, an item in inventory, or even a place. In other words, entity beans model real-world objects; these objects are usually persistent records in some kind of database. Our hypothetical cruise line will need entity beans that represent cabins, customers, ships, etc.
Session beans are an extension of the client application and are responsible for managing processes or tasks. A Ship bean provides methods for doing things directly to a ship but doesn’t say anything about the context under which those actions are taken. Booking passengers on the ship requires that we use a Ship bean, but 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, for example, the act of making a reservation. They have a lot to do with the relationships between different enterprise beans. A TravelAgent session bean, for example, might make use of a Cruise, a Cabin, and a Customer—all entity beans—to make a reservation.
The activity that a session bean represents is fundamentally transient: you start making a reservation, you do a bunch of work, and then it’s finished. A session bean doesn’t represent something in a database. Obviously, session 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 beans like TravelAgent, which is 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 record in the database—once the reservation is made, it’s done.
What makes this distinction difficult is that it’s extremely flexible. The relevant distinction for Enterprise JavaBeans is that an entity bean has persistent state; a session bean models interactions but doesn’t have persistent state.
A good way to understand the design of enterprise beans is to look at how you’d go about implementing one. To implement an enterprise bean, you need to define two interfaces and one or two classes:
The
remote interface for an
enterprise bean defines the bean’s business methods: the
methods a bean presents to the outside world to do its work. The
remote interface extends javax.ejb.EJBObject
,
which in turn extends java.rmi.Remote
.
(We’ll call the rather shadowy entity that actually implements
this interface the EJB object.)
The home
interface defines the bean’s life cycle methods: methods for
creating new beans, removing beans, and finding beans. The home
interface extends javax.ejb.EJBHome
, which in turn
extends java.rmi.Remote
. (We’ll call the
object that implements the home interface the EJB
home.)
The
bean class actually
implements the bean’s business methods. Note, however, that the
bean class usually does not implement the bean’s home or remote
interfaces. However, it must have methods matching the signatures of
the methods defined in the remote interface and must have methods
corresponding to some of the methods in the home interface. If this
sounds perfectly confusing, it is. We’ll try to clarify this as
we go along. An entity bean must implement
javax.ejb.EntityBean
; a session bean must
implement javax.ejb.SessionBean
. Both
EntityBean
and SessionBean
extend javax.ejb.EnterpriseBean
.
The
primary key is a very simple
class that provides a pointer into the database. Only entity beans
need a primary key; the only requirement for this class is that it
implements java.io.Serializable
.
The complexity—particularly all the confusion about classes implementing the methods of an interface but not implementing the interface itself—comes about because enterprise beans exist in the middle between some kind of client software and some kind of database. The client never interacts with a bean class directly; it always uses the methods of the bean’s home and remote interfaces to do its work, interacting with stubs that are generated automatically. (For that matter, a bean that needs the services of another bean is just another client: it uses the same stubs, rather than interacting with the bean class directly.)
There are also lots of interactions between a bean and its server. These interactions are managed by a "container,” which is responsible for presenting a uniform interface between the bean and the server. (Although it’s incorrect, many people use the terms “container” and "server” interchangeably. We won’t promise consistency ourselves. But it’s helpful to understand the difference.) The container is responsible for creating new instances of beans, making sure that 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 will take care of creating the mapping between entity beans and records in your database. Other tools generate a lot of code based on the home interface, the remote interface, and the bean class itself. The code generated does things like create the bean, store it in the database, and so on. This code (in addition to the stubs) is what actually implements the two interfaces, and is the reason your bean class doesn’t have to.
Before going on let’s first establish some
conventions. When we speak about an
enterprise bean as a whole, its remote interface, home interface,
bean class, and so forth, we will call it by its remote-interface
name, followed by the word “bean.” For example, an
enterprise bean that is developed to model a cabin on a ship will be
called the “Cabin bean.” Notice that we didn’t use
a constant width font for “Cabin.” We do this because we
are referring to all the parts of the bean (remote interface, home
interface, bean class, etc.) as a whole, not just one particular part
like the remote interface or bean class. When we are talking about
the remote interface of the Cabin bean we will use constant width.
For example, the remote interface for the Cabin bean is called the
Cabin
remote interface. Likewise, we use constant
width for the names of the classes that make up the other parts of
the bean. The bean class itself would be called
CabinBean
, the home interface
CabinHome
, and the primary key would be called
CabinPK
.
Having introduced the machinery, let’s look at how to build a bean. In this section, we will examine the Cabin bean, an entity bean that models a cabin on a cruise ship. Let’s start with its remote interface.
We’ll define the remote interface for a Cabin bean using the
interface called Cabin
, which defines business
methods for working with cabins. All remote-interface types extend
the javax.ejb.EJBObject
interface.
import java.rmi.RemoteException; public interface Cabin extends javax.ejb.EJBObject { public String getName() throws RemoteException; public void setName(String str) throws RemoteException; public int getDeckLevel() throws RemoteException; public void setDeckLevel(int level) throws RemoteException; }
These are methods for naming the cabin and methods for setting the
cabin’s deck level; you can probably imagine lots of other
methods that you’d need, but this is enough to get started. All
of these methods declare that they throw
RemoteException
, which is required of any method
that can be invoked through RMI. EJB requires the use of
Java RMI-IIOP
conventions, although the underlying protocol can be CORBA IIOP, Java
Remote Method Protocol ( JRMP), or some other protocol. Java RMI-IIOP
will be discussed in more detail in the next chapter.
The
home interface defines
life-cycle methods and methods for looking up beans. The home
interface extends javax.ejb.EJBHome
. We’ll
call the home interface for the Cabin bean
CabinHome
and define it like this:
import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.FinderException; public interface CabinHome extends javax.ejb.EJBHome { public Cabin create(int id) throws CreateException, RemoteException; public Cabin findByPrimaryKey(CabinPK pk) throws FinderException, RemoteException; }
The
create()
method will be responsible for initializing an instance of our bean.
If your application needs it, you can provide other
create()
methods, with different arguments.
In addition to the
findByPrimaryKey()
, you are free to define other
methods that provide convenient ways to look up Cabin beans—for
example, you might want to define a method called
findByShip()
that returns all the cabins on a
particular ship. Find methods like these are only used in
EntityBean
types and are not used in
SessionBean
types.
Now let’s look at an actual bean.
Here’s the code for the CabinBean
;
it’s a sparse implementation, but it will show you how the
pieces fit together:
import javax.ejb.EntityContext; public class CabinBean implements javax.ejb.EntityBean { public int id; public String name; public int deckLevel; // EJB 1.0: return void public CabinPK ejbCreate(int id){ this.id = id; // EJB 1.0 no return statement return null; } public void ejbPostCreate(int id){ // do nothing } public String getName(){ return name; } public void setName(String str){ name = str; } public int getDeckLevel(){ return deckLevel; } public void setDeckLevel(int level){ deckLevel = level; } public void setEntityContext(EntityContext ctx){ // not implemented } public void unsetEntityContext(){ // not implemented } public void ejbActivate(){ // not implemented } public void ejbPassivate(){ // not implemented } public void ejbLoad(){ // not implemented } public void ejbStore(){ // not implemented } public void ejbRemove(){ // not implemented } }
The //
EJB
1.0
comments indicate how to modify the code to
work with an EJB 1.0 server. As written, this code (and the other
examples in this book) assume EJB 1.1, unless otherwise noted.
The set and get methods for the
cabin’s name and deck level are the business methods of the
CabinBean
; they match the business methods defined
by the bean’s remote interface, Cabin
. The
CabinBean
class has state and business behavior
that models the concept of a cabin. The business methods are the only
methods that are visible to the client application; the other methods
are visible only to the EJB container. The other methods are required
by the EJB component model and are not really part of the bean
class’s public business definition.
The ejbCreate()
and
ejbPostCreate()
methods initialize the instance of
the bean class when a new cabin record is to be added to the
database. The last seven methods in the CabinBean
are defined in the javax.ejb.EntityBean
interface.
These methods are
state management callback methods. The EJB server invokes these
callback methods on the bean class when important state management
events occur. The ejbRemove()
method, for example,
notifies an entity bean that its data is about to be deleted from the
database. The ejbLoad()
and
ejbStore()
methods notify the bean instance that
its state is being read or written to the database. The
ejbActivate()
and
ejbPassivate()
methods notify the bean instance
that it is about to be activated or deactivated, a process that
conserves memory and other resources.
setEntityContext()
provides the bean with an
interface to the EJB server that allows the bean class to get
information about itself and its surroundings.
unsetEntityContext()
is called by the EJB server
to notify the bean instance that it is about to be dereferenced for
garbage collection.
All these callback methods provide the bean class with
notifications of
when an action is about to be taken, or was just taken, on the bean
class’s behalf by the EJB server. These notifications simply
inform the bean of an event, the bean doesn’t have to do
anything about it. The callback notifications tell the bean where it
is during its life cycle, when it is about to be loaded, removed,
deactivated, and so on. Most of the callback methods pertain to
persistence, which can be done automatically for the bean class by
the EJB server. Because the callback methods are defined in the
javax.ejb.EntityBean
interface, the bean class must implement
them, but it isn’t required to do anything meaningful with the
methods if it doesn’t need to. Our bean, the
CabinBean
, won’t need to do anything when
these callback methods are invoked, so these methods are empty
implementations. Details about these callback methods, when they are
called and how a bean should react, are covered in Chapter 6.
Certain public fields of an entity bean are stored in a database.
These fields are called
persistent fields. Determining how the data in
the database relates to the persistent fields of the bean class is
called
data mapping. When a bean is deployed into an
EJB server, its persistent fields must be mapped to the database. The
data used to populate persistent fields in the bean instance is
obtained using a primary key. The primary key is a pointer that helps
locate data that describes a unique record or entity in the database;
it is used in the findByPrimaryKey()
method of the
home interface to locate a specific entity. Primary keys are defined
by the bean developer and must be some type of serializable object.
Here’s the primary key for the Cabin bean:
public class CabinPK implements java.io.Serializable{ public int id; public int hashCode(){ return id; } public boolean equals(Object obj){ if (obj instanceof CabinPK){ if (((CabinPK)obj).id == id) return true; } return false; } }
Most EJB container vendors provide some kind of tool, available at deployment time, that helps to map the primary key and the bean’s persistent fields to the database. These kinds of tools may present the persistent fields of the bean as well as the structure of the database in a graphical presentation. The person deploying the bean simply ties the bean’s fields to its representation in the database, which could be relational database columns, an objectified version of the database, or a more direct mapping to an object database.
CabinBean
is an entity bean, but a
session bean
wouldn’t be all that different. It would extend
SessionBean
instead of
EntityBean
; it would have an
ejbCreate()
method that would initialize the
bean’s state, but no ejbPostCreate()
.
Session beans don’t have an ejbLoad()
or
ejbStore()
because session beans are not
persistent. While session beans have a
setSessionContext()
method, they don’t have
an unsetSessionContext()
method. Finally, a
session bean would provide an ejbRemove()
method,
which would be called to notify the bean that the client no longer
needs it. However, this method wouldn’t tell the bean that its
data was about to be removed from the database, because a session
bean doesn’t represent data in the database.
Session beans don’t have a primary key. That’s because session beans are not persistent themselves, so there is no need for key that maps to the database.
Much of the information about how beans are managed at runtime is not addressed in the interfaces and classes discussed previously. You may have noticed, for example, that we didn’t talk about how beans interact with security, transactions, naming, and other services common to distributed object systems. As you know from prior discussions, these types of primary services are handled automatically by the EJB CTM server, but the EJB server still needs to know how to apply the primary services to each bean class at runtime. To do this, we use deployment descriptors.
Deployment descriptors serve a function very similar to property files. They allow us to customize behavior of software (enterprise beans) at runtime without having to change the software itself. Property files are often used with applications, but deployment descriptors are specific to a class of enterprise bean. Deployment descriptors are also similar in purpose to 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.). Deployment descriptors allow certain runtime behaviors of beans to be customized, without altering the bean class or its interfaces.
When a bean class and its interfaces have been defined, a deployment descriptor for the bean is created and populated with data about the bean. Frequently, IDEs (integrated development environments) that support development of Enterprise JavaBeans will allow developers to graphically set up the deployment descriptors using visual utilities like property sheets. After the developer has set all the properties for a bean, the deployment descriptor is saved to a file. Once the deployment descriptor is complete and saved to a file, the bean can be packaged in a JAR file for deployment.
JAR ( J ava
ar chive) files are ZIP files that are used
specifically for packaging Java classes (and other resources such as
images) that are ready to be used in some type of application. JARs
are used for packaging applets, Java applications, JavaBeans, and
Enterprise JavaBeans. A JAR file containing one or more enterprise
beans includes the bean classes, remote interfaces, home interfaces,
and primary keys (EntityBean
types only), for each
bean. It also contains one deployment descriptor, which is used for
all the beans in the JAR files. When a bean is deployed, the
JAR’s path is given to the container’s deployment tools,
which read the JAR file. The container uses the deployment descriptor
to learn about the beans contained in the JAR file.
EJB 1.0 also requires information in the JAR manifest (a kind of table of contents for the JAR), to denote which entry points to the deployment descriptor. When a bean is deployed, the JAR’s path is given to the container’s deployment tools, which read the JAR file. The first thing read out of the JAR file after the manifest is the deployment descriptor.
EJB 1.1 doesn’t use the JAR’s manifest; the first thing read in the JAR is the deployment descriptor.
When the JAR file is read at deployment time, the container tools
read the deployment descriptor to learn about the bean and how it
should be managed at runtime. The deployment descriptor tells the
deployment tools what kind of beans are in the JAR file
(SessionBean
or EntityBean
),
how they should be managed in transactions, who has access to the
beans at runtime, and other runtime attributes of the beans. The
person who is deploying the bean can alter some of these settings,
like transactional and security access attributes, to customize the
bean for a particular application. Many container tools provide
property sheets for graphically reading and altering the deployment
descriptor when the bean is deployed. These graphical property sheets
are similar to those used by bean developers.
The deployment descriptors help the deployment tools to add beans to the EJB container. Once the bean is deployed, the properties described in the deployment descriptors will continue to be used to tell the EJB container how to manage the bean at runtime.
Enterprise JavaBeans Version 1.0 uses a set of serializable classes to set and store the deployment descriptor information. Instances of these classes are created and populated with deployment information when the bean is developed, then serialized to a file. The container deploying the bean deserializes the deployment descriptor objects and reads their properties to obtain the deployment information.
Here are some of the property methods defined in the main descriptor
class,
DeploymentDescriptor
. The method bodies have been
omitted; what’s important at this stage is to get a feel for
what methods are defined by a descriptor.
public abstract Class javax.ejb.deployment.DeploymentDescriptor extends Object implements Serializable { // The release version of the bean protected int versionNumber; // Get the AccessControlEntry objects for the enterprise bean. public AccessControlEntry[]getAccessControlEntries()
{} // Get the control descriptor at the specified index. public ControlDescriptorgetControlDescriptors(int index)
{} // Get the enterprise bean's full class name. public StringgetEnterpriseBeanClassName()
{} // Get enterprise bean's environment properties. public PropertiesgetEnvironmentProperties()
{} // Get the full name of the enterprise bean's home interface. public StringgetHomeInterfaceClassName()
{} // Get the full name of the enterprise bean's remote interface. public StringgetRemoteInterfaceClassName()
{} // Set the AccessControlEntry objects for the enterprise bean. public voidsetAccessControlEntries(AccessControlEntry values [])
{} // Set the control descriptor at the specified index. public voidsetControlDescriptors(int index, ControlDescriptor value)
{} // Set the enterprise bean's full class name. public voidsetEnterpriseBeanClassName(String value)
{} // Set enterprise bean's environment properties. public voidsetEnvironmentProperties(Properties value)
{} // Set the full name of the enterprise bean's home interface. public voidsetHomeInterfaceClassName(String value)
{} // Specify that the enterprise bean is reentrant. public voidsetReentrant(boolean value)
{} // Set the full name of the enterprise bean's remote interface. public voidsetRemoteInterfaceClassName(String value)
{} // ... Other set and get methods for properties follow. }
The classes used to provide deployment information are found in the
javax.ejb.deployment
package, which has five deployment
descriptor classes:
DeploymentDescriptor
The
DeploymentDescriptor
class is the abstract superclass for both
EntityDescriptor
and
SessionDescriptor
. It provides the accessor
methods for reading properties that describe the bean’s version
number, and the names of the classes for the bean’s remote
interface, home interface, and bean class. In addition, the
deployment descriptor provides access to the
ControlDescriptor
s and
AccessControlEntry
s.
ControlDescriptor
The ControlDescriptor
class provides accessor
methods for defining the security and transactional attributes of a
bean at runtime. ControlDescriptor
s can be applied
to the bean as a whole, or to specific methods of the bean. Any
method that doesn’t have a ControlDescriptor
uses the default properties defined by the
ControlDescriptor
for the bean itself. Security
properties in the ControlDescriptor
indicate how
AccessControlEntry
s are applied at runtime.
Transactional properties indicate how the bean or specific method
will be involved in transactions at runtime.
AccessControlEntry
Each
AccessControlEntry
identifies a person, group, or role that can access the bean or one
of its methods. Like ControlDescriptor
,
AccessControlEntry
can be applied to the bean as a
whole or to a specific method. An
AccessControlEntry
that is specific to a method
overrides the default AccessControlEntry
s set for
the bean. The AccessControlEntry
s are used in
combination with the security properties in the
ControlDescriptor
to provide more control over
runtime access to the bean and its methods.
EntityDescriptor
The
EntityDescriptor
class extends
DeploymentDescriptor
to provide properties
specific to an EntityBean
object. Entity bean
properties include the name of the primary key class and what
instance variables are managed automatically by the container.
SessionDescriptor
The
SessionDescriptor
class extends
DeploymentDescriptor
to provide properties
specific to a SessionBean
object. Session bean
properties include a timeout setting (how long a session can go
unused before it’s automatically removed) and a stateless
session property. The stateless session property indicates whether
the session is a stateless session bean or a stateful session bean.
(More about stateless and stateful session beans later.)
Several of the properties described by the deployment descriptors, such as transactional and security attributes, have not yet been discussed. Later we will discuss these topics in more detail, but for now it’s important that you understand that the deployment descriptors in EJB 1.0 are serialized class instances that describe the bean and some of its runtime behavior to the container.
Enterprise JavaBeans 1.1 dropped the serializable deployment descriptor classes used in EJB 1.0 in favor of a more flexible file format based on XML (Ex tensible M arkup Language). The new XML deployment descriptors are text files structured according to a standard EJB DTD (Document Type Definition) that can be extended so the type of deployment information stored can evolve as the specification evolves. Chapter 10 provides a a detailed description of EJB 1.1 deployment descriptors. This section provides a brief overview of XML deployment descriptors.
The following deployment descriptor might be used to describe the Cabin bean:
<?xml version="1.0"?> <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.2//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd"> <ejb-jar> <enterprise-beans> <entity> <ejb-name>CabinEJB</ejb-name> <home>com.titan.cabin.CabinHome</home> <remote>com.titan.cabin.Cabin</remote> <ejb-class>com.titan.cabin.CabinBean</ejb-class> <prim-key-class>com.titan.cabin.CabinPK</prim-key-class> <persistence-type>Container</persistence-type> <reentrant>False</reentrant> </entity> </enterprise-beans> </ejb-jar>
The deployment descriptor for a real bean would have a lot more information; this example simply illustrates the type of information that you’ll find in an XML deployment descriptor.
The second element in any XML document is
!DOCTYPE
. This element
describes the organization that defined the DTD for the XML document,
the DTD’s version, and a URL location of the DTD. The DTD
describes how a particular XML document is structured.
All the other elements in the XML document are specific to EJB 1.1. They do not represent all the elements used in deployment descriptors, but they illustrate the types of elements that are used. Here’s what the elements mean:
ejb-jar
The root of the XML deployment descriptor. All other elements must be
nested below this one. It must contain one
enterprise-beans
element as well as other optional
elements.
enterprise-beans
Contains declarations for all the beans described by this XML
document. It may contain entity
and
session
elements, which describe entity beans and
session beans respectively.
entity
Describes an entity bean and its deployment information. There must
be one of these elements for every entity bean described by the XML
deployment descriptor. (The session
element is
used in the same way to describe a session bean.)
ejb-name
The descriptive name of the bean. It’s the name we use for the bean in conversation, when talking about the bean component as a whole.
home
The fully qualified class name of the home interface. This is the interface that defines the life-cycle behaviors (create, find, remove) of the bean.
remote
The fully qualified class name of the remote interface. This is the interface that defines the bean’s business methods.
ejb-class
The fully qualified class name of the bean class. This is the class that implements the business methods of the bean.
prim-key-class
The fully qualified class name of the bean’s primary key. The primary key is used to find the bean data in the database.
The last two elements in the deployment descriptor, the persistence-type and reentrant elements, express the persistence strategy and concurrency policies of the entity bean. These elements are explained in more detail later in the book.
As you progress through this book, you will be introduced to the elements that describe concepts we have not covered yet, so don’t worry about knowing all of the things you might find in a deployment descriptor.
We’ve done a lot of hand waving about the strange relationships between an enterprise bean and its interfaces. Now it’s time to talk a little more precisely about what’s going on. Unfortunately, we can’t talk as precisely as we’d like. There are a number of ways for an EJB container to implement these relationships; we’ll show some of the possibilities.
The two missing pieces are the EJB object itself and the EJB home. You will probably never see the EJB home and EJB object classes because their class definitions are proprietary to the vendor’s EJB implementation and are generally not made public. This is good 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 CTMs and support distributed objects. It makes sense for system-level developers to apply their skills to mechanics of managing distributed objects but leave the business logic to you, the application developer. Let’s talk briefly about the EJB object and the EJB home so you understand the missing pieces in the big picture.
This chapter has said a lot about a bean’s remote interface,
which extends the
EJBObject
interface.
Who implements that interface? Clearly, the client
stub: we understand that
much. But what about the server
side?
On the server side, an EJB object is a distributed object that
implements the remote interface of the bean. It wraps the bean
instance—that is, the enterprise bean class you’ve
created (in our example, the CabinBean
)—on
the server and expands its functionality to include
javax.ejb.EJBObject
behavior. The EJB object is
generated by the utilities provided by the vendor of your EJB
container and is based on the bean classes and the information
provided by the deployment descriptor. The EJB object wraps the bean
instance and works with the container to apply transactions,
security, and other system-level operations to the bean at runtime.
Chapter 3 talks more about the EJB object’s
role with regard to system-level operations.
There are a number of strategies that a vendor can use to implement the EJB object; Chapter 2 illustrates three possibilities.
In Figure 2.1(a) you see that the EJB object is a classic wrapper because it holds a reference to the bean class and delegates the requests to the bean. Chapter 2(b) shows that the EJB object class actually extends the bean class, adding functionality specific to the EJB container. In Chapter 2(c), you see that the bean class is no longer included in the model. In this case, the EJB object has both a proprietary implementation required by the EJB container and bean class method implementations that were copied from the bean class’s definition.
The EJB object design that is shown in Chapter 2(a) is perhaps the most common. Throughout this book, particularly in the next chapter, we will explain how EJB works with the assumption that the EJB object wraps the bean class instance as depicted in Figure 2.1(a). But the other implementations are used; it shouldn’t make a difference which one your vendor has chosen. The bottom line is that you never really know much about the EJB object: its implementation is up to the vendor. Knowing that it exists and knowing that its existence answers a lot of questions about how enterprise beans are structured, should be sufficient. Everything that any client (including other enterprise beans) really needs to know about any bean is described by the remote and home interfaces.
The EJB home is a lot like the EJB object. It’s another class that’s generated automatically when you install an enterprise bean in a container. It implements all the methods defined by the home interface and is responsible for helping the container in managing the bean’s life cycle. Working closely with the EJB container, the EJB home is responsible for locating, creating, and removing enterprise beans. This may involve working with the EJB server’s resource managers, instance pooling, and persistence mechanisms, the details of which are hidden from the developer.
For
example, when a create method is invoked on the home interface, the
EJB home creates an instance of the EJB object which references a
bean instance of the appropriate type. Once the bean instance is
associated with the EJB object, the instance’s matching
ejbCreate()
method is called. In the case of an
entity bean, a new record is inserted into the database. With session
beans the instance is simply initialized. Once the
ejbCreate()
method has completed, the EJB home
returns a remote reference (i.e., a stub) for the EJB object to the
client. The client can then begin to work with the EJB object by
invoking
business methods using the stub. The
stub relays the methods to the EJB object; in turn, the EJB object
delegates those method calls to the bean instance.
Figure 2.2 illustrates the architecture of EJB with the EJB home and EJB object implementing the home interface and remote interface respectively. The bean class is also shown as being wrapped by the EJB object.
The EJB object and EJB home are generated during the deployment process. After the files that define the bean (the home interface, the remote interface, and the bean classes) have been packaged into a JAR file, the bean is ready to be deployed: that is, added to an EJB container so that it can be accessed as a distributed component. During the deployment process, tools provided by the EJB container vendor generate the EJB object and EJB home classes by examining the deployment descriptor and the other interfaces and classes in the JAR file.