Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Create forward-compatible beans in EJB, Part 1

How to write EJB 1.0 beans to port to EJB 1.1 servers

  • Print
  • Feedback

Page 6 of 6

The EJB 1.1 specification also supports the use of the JNDI ENC to access factories for other resources like the Java Messaging Service (JMS), Java Mail, and URL with appropriate JNDI names (for example, java:comp/env/jms for the JMS). You can enhance PortableContext to support the use of these resources as well -- an exercise I will leave up to you.

Bean references

Frequently beans use references to other beans to accomplish tasks. EJB 1.0 and EJB 1.1 differ in how references to the bean homes are obtained. EJB 1.0 relies on the conventional use of JNDI, just like a client application, to obtain a remote reference to a bean home. EJB 1.1 allows bean homes to be included in the JNDI ENC, which gives the deployer more control over the network location of beans and how they are accessed. Those differences can also be encapsulated (hidden) in the PortableContext, as illustrated below.

List 9-A. EJB References in PortableContext1_0 (EJB 1.0)
import javax.ejb.EJBContext;
import java.util.Properties;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.naming.Context;
public class PortableContext1_0 extends PortableContext {
  public Object lookup(String name, Class type) 
      throws PortableContextException {
    try {
      Properties props = ejbContext.getEnvironment();
      String value = props.getProperty(name);
      if (value == null)
             return null;
      if (name.startsWith("java:comp/env/jdbc"))
             return DriverManager.getConnection(value);     else if (name.startsWith("java:comp/env/ejb")) {
             InitialContext jndiContext = getInitialContext();
             return jndiContext.lookup(value);
      } 
      else {
            if (type == String.class)
                 return value;
            else
                 return primitiveWrapper(value, type);
      } 
    } catch(Exception e) {
      throw new PortableContextException(e);
    }
  }
  private InitialContext getInitialContext() throws Exception {
    Properties p = new Properties();
    p.put(Context.INITIAL_CONTEXT_FACTORY,
      "weblogic.jndi.T3InitialContextFactory");
    p.put(Context.PROVIDER_URL, "t3://localhost:7001");
    return new InitialContext(p);
  }
  private Object primitiveWrapper(String value, Class type)
      throws PortableContextException {
    if (type == Double.class)
      return new Double(value);
    if (type == Integer.class)
      return new Integer(value);
    if (type == Boolean.class)
      return new Boolean(value);
    if (type == Long.class)
      return new Long(value);
    if (type == Byte.class)
      return new Byte(value);
    if (type == Short.class)
      return new Short(value);
    if (type == Float.class)
      return new Float(value);
    else
      throw new PortableContextException();
  }
}


List 9-B. EJB References in PortableContext1_1 (EJB 1.1)
import javax.ejb.EJBContext;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.SQLException;
import javax.rmi.PortableRemoteObject;
 
 
 
public class PortableContext1_1 extends PortableContext {
  InitialContext jndiContext;
 
  public Object lookup(String name, Class type){
      throws PortableContextException
    try {
      jndiContext = new InitialContext();
      Object value = jndiContext.lookup(name);
      if (name.startsWith("java:comp/env/jdbc")){
        DataSource ds = (DataSource)value;
        return ds.getConnection();
      } else if (name.startsWith("java:comp/env/ejb")) {
        return PortableRemoteObject.narrow(value, type);
      } else
        return value;
    } catch(NamingException ne) {
      throw new PortableContextException(ne);
    } catch(SQLException se) {
      throw new PortableContextException(se);
    }
  }
}


With the EJB 1.0 implementation (PortableContext1_0), the bean home is obtained using conventional JNDI access with security authentication and loading of the JNDI service provider. This example uses BEA WebLogic 3.x conventions. If you use a different EJB server, substitute the appropriate properties for that platform.

In EJB 1.1, you can obtain the bean home from the JNDI environment context without having to authenticate or load the service provider. EJB 1.1 requires that the javax.rmi.PortableRemoteObject.narrow() method be used to explicitly cast the home's remote reference to its appropriate type. The use of PortableRemoteObject is required to support Java RMI-IIOP (Remote Method Invocation over Internet Inter-ORB Protocol), which is based on CORBA reference types that do not support native casting. You can take advantage of the Class type variable used in the lookup() method to specify the target interface in the PortableRemoteObject.narrow() method.

List 10 shows how the remote reference to a bean's EJB home is obtained in a forward-portable bean.

List 10. Using the PortableContext to access a bean reference in both EJB 1.0 and EJB 1.1
import javax.ejb.SessionContext;
  public class TellerBean implements javax.ejb.SessionBean {
    SessionContext ejbContext;
    PortableContext portableContext = null;
    public void setSessionContext(SessionContext ctx) {
      ejbContext = ctx;
      setPortableContext();
    }
  public void transfer(int accountSource, int accountTarget, amount) 
      throws TransferException {
    try {
      AccountHome accountHome  = (AccountHome)
        portableContext.lookup("java:comp/env/ejb/AccountHome", AccountHome.class);
      Account as = accountHome.findByPrimaryKey(new AccountPK(accountSource));
      Account at = accountHome.findByPrimaryKey(new AccountPK(accountTarget));
      as.withdraw(amount);
      at.deposit(amount);
      ...
    }
}


Wrapping Up

This installment on forward compatibility has presented a strategy for mitigating forward compatibility problems related to runtime access to environment properties, resources, and other beans. Source code for the PortableContext and its implementations are available at my Web site (see EJBNow in Resources).

The next and final installment in this series will continue to enhance the PortableContext to encapsulate differences in security. The next installment will also explore the application of the PortableContext to make beans portable between brands of EJB servers. In addition, it will cover issues specific to entity bean forward compatibility and deployment descriptors (*.ser to xml).

About the author

Richard Monson-Haefel is an EJB expert for jGuru.com and the author of Enterprise JavaBeans published by O'Reilly & Associates (1999). Richard would like to thank Chris Raber of Gemstone, who was a technical reviewer of this article and a contributor in the development of the PortableContext. Learn more about Richard at jGuru.com. JavaWorld and jGuru have formed a partnership to help the community better understand server-side Java technology. Together, JavaWorld and jGuru are jointly producing articles, free educational Web events, and working together on the JavaWorld bookstore and Web-based training.

Read more about Enterprise Java in JavaWorld's Enterprise Java section.

  • Print
  • Feedback

Resources