EJB 2.0 Specification Release Review
05/10/2001
With little fanfare, Sun released the second public final draft of
the EJB 2.0 specification last week. Even though the specification is
in the final stages before acceptance, this update contains extensive
changes. Application server vendors and developers who have been
unhappy with a proposed implementation of dependent objects have
pushed for changes. Some background information on these issues can
be found in my earlier articles
Most of the significant changes in this latest revision involve the
removal of dependent objects and the introduction of local interfaces.
This article will discuss local interfaces, their proposed
implementation, and issues that developers may expect to encounter
when dealing with this technology.
What are Local Interfaces?
As everyone knows, session and entity beans have had home and
remote interfaces, where business operations are defined. The latest
EJB specification introduces the possibility of having local home and
local interfaces in addition to the existing remote home and remote
interfaces. Developers should be aware that remote interfaces have
been renamed to "component" interfaces in the latest, public, final
draft. The rest of this article will continue to use "remote"
interfaces for simplicity.
The specification now separates clients that access an EJB into two
types:
- remote clients that reside in a different virtual machine than the EJB container and,
- local clients that are collocated in the same virtual machine with the EJB container.
As a result of this distinction, it makes sense to expect local
clients to have optimized access to an EJB's operations as opposed to
remote clients that are required to use RMI semantics.
The EJB specification defines just that.
Local clients that access the local home or local interface of an
EJB are granted optimized access by bypassing RMI semantics in favor
of direct method invocation (using pass by reference). Local
interfaces provide an appealing new aspect to developers. Methods
invoked on a local home or local interface of an EJB will only be
invoked using pass by reference semantics. Essentially, it's nothing
more than a method invocation on a local Java object.
Writing local home and local interfaces is very similar to writing
remote and remote home interfaces. Generally, they follow the same
rules with a few exceptions:
- The throws clause of all methods in the local home and local interfaces must not throw
java.rmi.RemoteException.
- A local home interface must extend
EJBLocalHome instead of EJBHome.
- A local interface must extend
EJBLocalObject instead of EJBObject.
Why Local Interfaces?
In the first public final draft of the EJB 2.0 specification,
dependent objects were the proposed mechanism for adding finer-grained
access to entity EJBs. For example, a Person entity EJB describing
all the personal information of a human being might be a
coarse-grained object accessed directly by a presentation layer. The
Person entity EJB may want to have a reference to a fine-grained
Address persistent object. The bean developer will want to maintain a
separation between the Person EJB and the Address persistent object
that it references. In the previous public final draft specification,
there were two ways to implement this using CMP.
First, create Person and Address as CMP entity EJBs that participate
in a relationship. This would require Address to be a coarse-grained
persistent object that is accessible to all objects in the system via
RMI. The Person EJB would not have optimized access to the Address
bean since it must use RMI semantics.
Second, create Person as a CMP entity EJB and create Address as a
dependent object that participates in a relationship with Person. The
Address dependent object would be accessible by local method
invocations but has a different implementation technique than entity
EJBs.
Entity EJBs have always been considered coarse-grained persistence
objects due to a variety of factors. In the first place, the only
portable technique that could be used to access an entity EJB was an
RMI invocation. Second, every method invocation had request-level
interception that added security, persistence, and transaction
overhead that may or may not be necessary. And, third, the the 1.1 CMP
model of entity EJBs that mapped attributes of the bean class to
persistent fields made it extremely difficult to perform optimized
data access techniques. These techniques include partial field
loading, optimized writes of modified fields, and lazy loading of
fields. Since it was impossible for a container to determine which
fields were being accessed on any given method invocation, most
containers had to treat the persistent fields of the bean as a
holistic group as opposed to multiple groups of fields that can be
managed separately.
It was well understood by the development community that a
mechanism to provide fine-grained, local access to persistent objects
was needed. The dependent object implementation ultimately fell into
unfavorable status because of its awkward implementation style.
Enter local interfaces. The specification authors wanted to come up
with a mechanism that allowed developers to create entity EJBs that
are coarse-grained and fine-grained. By adding an additional
interface to an entity EJB, developers would not have to change the
techniques which they've already mastered. Local interfaces allow
developers to take existing entity EJBs and quickly separate the way
in which the bean is accessed by placing different operations into the
remote or local interfaces. Local interfaces provide all sorts of
benefits and headaches that are discussed below.
If the specification authors wanted to allow methods to be
accessible remotely and locally, why didn't they just include a
deployment descriptor tag that allows the bean developer or deployer
to specify how any given method should be invoked? This was debated
heatedly, and there are several reasons for creating separate remote
and local interfaces, as opposed to allowing a container to optimize
access to certain methods of a remote interface:
- By leaving all business operations as part of a remote interface,
containers that provided local optimized access to a method would be
breaking RMI semantics. Developers that code to a remote method
invocation expect certain behavioral factors to occur such as input
and return parameters being passed by value. Runtime optimizations of
a remote method invocation into a local call that has parameters
passed by reference would fundamentally break the semantics driven by
the interface.
- Compilers can provide stronger type checking for clients that make
use of local interfaces. Since local interfaces have different
semantics than remote interfaces, compilers can provide some minimal
type checking and constraint analysis around how a client is
attempting to use a local interface.