A Brief Overview of EJBs

In what follows you will find a highly simplified overview of the EJB technology. This overview, as well as the coverage in the rest of this chapter, is based on the EJB 2.0 specification. The concepts are illustrated with source code from a working program, packaged as Example ch10-ex1, consisting of a simple bean named Echo with the method String echo(String arg). As the name and method signature suggest, this method simply returns its string argument.

In this section, we look at the source code fragments of this example. The complete set of source and execution script files can be found in the subdirectory srcjsbookch10ex1 of the JSTK installation directory. For our experimentation, we assume that all the example sources are available in a directory rooted at c:ch10, with the same directory structure as in the JSTK installation tree. The next section, Working With WebLogic Server 7.0, describes how to build, deploy and run this application.

A Bean Provider implements an EJB as a collection of the EJB component interface, home interface and bean implementation class. The component interface declares a set of business methods available to the clients. A client program gets hold of the stub implementing home interface by doing a JNDI (Java Naming and Directory Interface) lookup at the Server hosting the beans. The home interface allows a client to get hold of the bean instance, either by creating it or getting a reference to an existing instance. The component and home interfaces together constitute the bean client view.

Component and home interfaces can be either remote or local. The remote component interface extends interface javax.ejb.EJBObject and the remote home interface extends interface javax.ejb.EJBHome. As is the case with RMI remote interfaces, methods of EJB remote and home interface must declare the exception java.rmi.RemoteException to be thrown in their throw clause. In fact, interfaces EJBObject and EJBHome extend java.rmi.Remote, the base interface for RMI server classes.

The remote component interface for our example bean is shown below:

// File: ex1echoEcho.java. Remote component interface for
// EchoBean
public interface Echo extends javax.ejb.EJBObject {
  public  String echo(String arg) throws java.rmi.RemoteException;
}

This interface declares the business method echo(String arg). Next, look at its home interface:

// File: ex1echoEchoHome.java. Remote home interface for
// EchoBean
public interface EchoHome extends javax.ejb.EJBHome {
  Echo create()
    throws javax.ejb.CreateException, java.rmi.RemoteException;
}

It is the responsibility of the EJB container and associated tools to generate concrete client and server side classes corresponding to the home interface. As we see later, WebLogic Server has an EJB Compiler program, weblogic.ejbc, which generates client-side stub classes.

All communication between a client and a remote EJB happens using RMI and is intermediated by the container. This intermediation allows the container to intercept the method invocations and perform security checks, transaction-related processing and other system-level functions.

The use of RMI semantics for EJB method invocation implies serialization and deserialization of argument and return objects. These operations are expensive. As the system-level services supported by EJBs can be useful for local invocation as well, it makes sense to bypass serialization and deserialization operations for local calls. To address this, local component and home interfaces were introduced in EJB 2.0. A local component interface extends the interface javax.ejb.EJBLocalObject and a local home interface extends the interface javax.ejb.EJBLocalHome. Use of local interfaces mandates co-location of the client and the EJB within the same JVM and the use of object references for passing method arguments and return values. This arrangement is suitable for fine-grained EJBs and can improve performance significantly. The use of remote component and home interfaces implies serialization and deserialization of arguments and return values, even if the client and the EJB are deployed within the same JVM. This extra processing is avoided with local component and home interfaces. However, the intermediation by the container still happens and security, transactions, and so on are enforced.

Usually, an EJB will have either the remote interfaces or the local interfaces, but not both.[1] This is logical, as the beans developed for access through local interfaces may not be suitable for access through remote interfaces and vice versa.

[1] However, the EJB specification doesn't preclude the simultaneous presence of both remote and local interfaces for a given bean.

There are three different types of enterprise beans: entity beans, session beans and message-driven beans. An entity bean represents an object view of a business data record stored in a persistent store. In contrast, a session bean implements business logic and is executed on the server on behalf of the client. A session bean could be stateful or stateless. A stateful session bean is associated with a particular client across invocations and maintains client state, whereas a stateless session bean maintains no client state and can be reused for different clients. A message-driven bean is quite different from both entity and session beans in the sense that it doesn't expose its functionality through methods. It gets associated with a JMS (Java Message Service) destination, either JMS Queue or Topic, and executes its onMessage() method on receipt of a JMS message. A bean implementation class must implement one of the following interfaces: javax.ejb.EntityBean, javax.ejb.SessionBean, or javax.ejb.MessageDrivenBean, depending on whether the bean is an entity bean, a session bean or a message-driven bean.

For illustration of security concepts, we will stick with our example bean, which happens to be a stateless-session bean. The implementation class of the example bean, corresponding to the component and home interfaces presented earlier, is shown in Listing 10-1:

Listing 10-1. Class EchoBean in source file EchoBean.java
// File: ex1echoEchoBean.java
public class EchoBean implements javax.ejb.SessionBean {
  private javax.ejb.SessionContext ctx;

  public void ejbActivate() {
    System.out.println("EchoBean.ejbActivate called");
  }
  public void ejbRemove() {
    System.out.println("EchoBean.ejbRemove called");
  }
  public void ejbPassivate() {
    System.out.println("EchoBean.ejbPassivate called");
  }
  public void setSessionContext(javax.ejb.SessionContext ctx) {
    System.out.println("EchoBean.setSessionContext called");
    this.ctx = ctx;
  }
  public void ejbCreate () throws CreateException {
    System.out.println("EchoBean.ejbCreate called");
  }
  public String echo(String arg) {
    System.out.println("--- BEGIN EchoBean.echo("" + arg + "") ---");
    System.out.println("--- END EchoBean.echo("" + arg + "") ---");
    return arg;
  }
}

Make note of the callback methods ejbActivate(), ejbRemove(), ejbPassivate(), ejbCreate() etc. These methods are invoked by the EJB container on bean state changes and allow the bean implementer to run code within these methods. As we have nothing specific to run in this example, except for setSessionContext() which allows the program to keep a reference to the SessionContext object associated with the bean, we simply print a message to indicate the execution of a particular method.

Information about all the different pieces of an EJB is stored in a deployment descriptor file named ejb-jar.xml. This file for our current example is shown in Listing 10-2.

Listing 10-2. Deployment Descriptor file ejb-jar.xml for the example bean
// File: ex1META-INFejb-jar.xml
<?xml version="1.0"?>

<!DOCTYPE ejb-jar PUBLIC
'-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN'
'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>

<ejb-jar>
  <enterprise-beans>
    <session>
      <ejb-name>Echo</ejb-name>
						<home>echo.EchoHome</home>
						<remote>echo.Echo</remote>
						<ejb-class>echo.EchoBean</ejb-class>
						<session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
    </session>
  </enterprise-beans>
  <ejb-client-jar>echo_client.jar</ejb-client-jar>
</ejb-jar>

In this simple case, the deployment descriptor essentially specifies that the EJB is a stateless-session bean, its name is "Echo", the implementation class is echo.EchoBean and so on. It also specifies a jar filename, echo_client.jar, through the element ejb-client-jar. The EJB container or a tool provided with the container is responsible for generating this jar file. The class files corresponding to component and home interfaces are archived in this generated jar file.

Under RMI, the server program is responsible for registering the remote objects to a RMI Registry and the clients get a remote reference by looking up this registry. What is the equivalent mechanism for EJBs? An EJB container is responsible for making all deployed EJBs accessible through a JNDI ENC (Environment Naming Context). A remote client can obtain this context by specifying the URL of the EJB server as input to the javax.naming.InitialContext class. The specific steps are illustrated in the client code, shown in Listing 10-3.

Listing 10-3. Example client code in the source file Client.java
// File: client/Client.java
package client;

import javax.naming.Context;
import echo.EchoHome;
import echo.Echo;

public class Client {
  private static String JNDI_FACTORY =
      "weblogic.jndi.WLInitialContextFactory";

  public static void main(String[] args) throws Exception {
    if (args.length < 1){
      System.out.println("Usage:: java client.Client <url>");
    return;
  }
  String url = args[0];

    // Get JNDI Environment Naming Context
    java.util.Properties h = new java.util.Properties();
    h.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
    h.put(Context.PROVIDER_URL, url);
    Context ctx = new javax.naming.InitialContext(h);

    Object home = ctx.lookup("ex1-echo-EchoHome");
    EchoHome ehome = (EchoHome)narrow(home, EchoHome.class);
    Echo estub = (Echo)narrow(ehome.create(), Echo.class);

    String msg = "Hello, World!!";
    System.out.println("Calling Echo..echo("" + msg + "") ...");
    String resp = estub.echo(msg);
    System.out.println("... Echo.echo("" + msg + "") = " + resp);

    System.out.println("Echo Client Executed successfully.");
  }

  private static Object narrow(Object o, Class c){
    return javax.rmi.PortableRemoteObject.narrow(o, c);
  }
}

The client program takes the URL of the target App Server as a command line argument and uses it to initialize the JNDI Environment Naming Context. The above code uses WebLogic's JNDI provider weblogic.jndi.WLInitialContextFactory for this purpose, but it could be any client-side JNDI provider. For example, you could use the JNDI provider com.sun.jndi.cosnaming.CNCtxFactory that comes with Sun's J2SE v1.4 SDK. But this provider will work only for IIOP URLs of the form iiop://server:port and RMI-IIOP based interactions. Compliance with J2EE 1.3 mandates interoperability through IIOP protocol among App Servers from different vendors.

Most of the App Servers support full RMI semantics in EJB calls as per J2SE Java RMI protocol or through some other proprietary protocol. WebLogic Server supports RMI invocations through its own proprietary protocol known as the t3 protocol. A WebLogic Server URL with t3 protocol has the form t3://server:port.

You must have noticed that the client program locates the stub corresponding to the home interface by specifying JNDI name "ex1-echo-EchoHome". This name is specified for a bean at deployment time in an App Server specific manner. We learn how to do this for the WebLogic Server in the next section, while installing BEA WebLogic Server software, configuring a WebLogic domain, compiling and deploying the example bean and running the client.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.145.217