Book Home Enterprise JavaBeans Search this book

D.4. The Default JNDI Context

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.

D.4.1. RMI over IIOP Narrowing

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.



Library Navigation Links

Copyright © 2001 O'Reilly & Associates. All rights reserved.