Environment variables have undergone a fairly
[a-z]adical change. Environment properties in
EJB 1.0 are a powerful mechanism for modifying the behavior of a
component without changing the component’s code. In EJB 1.0,
the environment properties are accessible to the bean through the
EJBContext.getEnvironment()
method, are set by the
bean developer, and can be modified by the deployer. In EJB 1.0, the
environment variables might, for example, be used to set a maximum
withdraw amount for an account bean, as in the following code:
// EJB 1.0 public class AccountBean implements javax.ejb.EntityBean { public EntityContext context; public void withdraw(double amount) throws MaximumLimitException { try { Properties environment = context.getEnvironment(); String value = environment.getProperty("withdraw_limit"); Double limit = new Double(value); if ( amount > limit.doubleValue()) { throw new MaximumLimitException(); else { // continue processing } } } }
EJB 1.1 changes the environment properties from the
java.util.Properties
class, used in EJB 1.0, to a
set of JNDI entries that exist in a name space called the
environment naming context. All deployed beans
in EJB 1.1 have an environment naming context (default JNDI context)
that can be accessed using the JNDI API. This default JNDI context
provides a set of immutable JNDI entries specific to each type of
bean. The default JNDI context provides the bean with access to
environment variables which can be of type String
or one of several primitive wrappers including
Double
, Float
,
Integer
, or Boolean
. The
entries are defined in the XML deployment descriptor using special
tags specific to the environment naming context. Here is an example
of how the default JNDI context is used at runtime by an EJB 1.1
bean:
// EJB 1.1 public class AccountBean implements javax.ejb.EntityBean { public EntityContext context; public void withdraw(double amount) throws MaximumLimitException { try { InitialContext initCxt = InitialContext(); Context defaultCxt = (Context)initCxt.lookup("java:comp/env"); Double limit = (Double) defaultCxt.lookup("java:comp/env/withdraw_limit"); if ( amount > limit.doubleValue()) { throw new MaximumLimitException(); else { // continue processing } } } }
EJB 1.1-compliant servers are not required to support the EJB 1.0
environment properties, which are available through the
EJBContext
. The
getEnvironment()
method has been deprecated and
will throw a runtime exception for EJB 1.1 servers that don’t
support backward compatibility.
Environment properties are only one of three sets of values that can
be accessed through the default JNDI context. The default JNDI
context is also used as a repository for linking to predefined
resources and beans. When developing a bean, the bean developer can
identify the types of resources and enterprise beans that will be
referenced in the bean and bind them to the default JNDI context.
This simplifies the process of looking up and obtaining bean
references within beans, as well as locating and using resources like
a JDBC database connection. The bean developer defines the types of
beans and resources associated with the default JNDI entries in the
XML deployment descriptor. The following code shows how a bean uses
its default JNDI context to look up a bean and a JDBC
DataSource
:
// EJB 1.1
public class TellerBean implements javax.ejb.SessionBean {
public void transfer(int sourceID, int targetID, double amount) {
InitialContext initCtx = new InitialContext();
// look up up the Account home
AccountHome acctHome =
(AccountHome)initCtx.lookup("java:comp/env/ejb/AccountHome");
// transfer the money
Account source = acctHome.findByPrimaryKey(
new AccountKey(sourceID));
Account target = acctHome.findByPrimaryKey(
new AccountKey(targetID));
source.withdraw(amount);
target.deposit(amount);
// Look up a the JDBC data source for recording transactions
javax.sql.DataSource dataSource =
(javax.sql.DataSource)initCtx.lookup("java:comp/env/jdbc/log");
java.sql.Connection con = dataSource.getConnection();
// continue processing: insert a log recording the transaction
}
}
EJB 1.1 standardizes on the use of resource connection factories to access resources such as a JDBC connection. A
resource factory provides access to resources in a manner that allows
the container to manage the use of the resource. The use of the
javax.sql.DataSource
is a perfect example. It
provides the bean with a JDBC connection that is managed
transactionally and securely by the EJB container. In addition to
JDBC, resource factories for the Java Messaging Service can also be
used to obtain and manage access to an asynchronous message service.
The default JNDI context provides a powerful mechanism for obtaining predefined environment properties, bean references, and resource factories. It standardizes access to enterprise bean’s environment through JNDI and lays the groundwork for future enhancements. As new facilities and services are made available to beans, they too can be accessed through the default JNDI context. A good example is the plan to provide a “connector” service that will allow beans to connect to legacy or “backend” systems using standard resource factories.
EJB 1.1 requires the use of Java RMI-IIOP reference and argument types when accessing enterprise beans from a client. EJB 1.1 servers are not required, however, to use IIOP as the distributed object protocol. They are only required to support the semantics and types used in Java RMI-IIOP.
Java RMI-IIOP requires that the remote references be explicitly
narrowed when returned as supertypes from mechanisms like the JNDI
context, Handle.getEJBObject()
,
EJBContext.getEJBObject()
, etc. Explicitly
narrowing a remote reference is necessary because CORBA doesn’t
support casting. To support RMI over IIOP we would change the line
that obtains a reference to the AccountHome
so
that it looks as follows:
// EJB 1.1 using RMI over IIOP InitialContext initCtx = new InitialContext(); Object ref = initCtx.lookup("java:comp/env/ejb/AccountHome"); AccountHome acctHome = (AccountHome) javax.rmi.PortableRemoteObject.narrow(ref, AccountHome.class);
The javax.rmi.PortableRemoteObject
class is part
of the RMI-IIOP extension package.