Skip Headers

Oracle Application Server Containers for J2EE Enterprise JavaBeans Developer's Guide 10g (9.0.4) Part Number B10324-01 |
Home | Contents | Index

# 2
EJB Primer

After you have installed Oracle Application Server Containers for J2EE (OC4J) and configured the base server and default Web site, you can start developing J2EE applications. This chapter assumes that you have a working familiarity with simple J2EE concepts and a basic understanding for EJB development.

The following subjects describe how to develop and deploy EJB applications with OC4J:

- Develop EJBs--Developing and testing an EJB module within the standard J2EE specification.

- Prepare the EJB Application for Assembly--Before deploying, you must modify an XML file that acts as a manifest file for the enterprise application.

- Deploy the Enterprise Application to OC4J--Archive the enterprise Java application into an Enterprise ARchive (EAR) file and deploy it to OC4J.

This chapter uses a stateless session bean example to show you each development phase and deployment steps for an EJB. As an introduction to EJBs, a simple EJB with a basic OC4J-specific configuration is used. You can download the stateless session bean example from the OC4J sample code page on the OTN Web site.

## Develop EJBs

You develop EJB components for the OC4J environment in the same way as in any other standard J2EE environment. Here are the steps to develop EJBs:

1. Create the Development Directory--Create a development directory for the enterprise application (as Figure 2-1 shows).

2. Implement the EJB--Develop your EJB with its home interfaces, component interfaces, and bean implementation.

3. Access the EJB--Develop the client to access the bean through the remote or local interface.

4. Create the Deployment Descriptor--Create the standard J2EE EJB deployment descriptor for all beans in your EJB application.

5. Archive the EJB Application--Archive your EJB files into a JAR file.

### Create the Development Directory

Although you can develop your application in any manner, we encourage you to use consistent naming for locating your application easily. One method would be to implement your enterprise Java application under a single parent directory structure, separating each module of the application into its own subdirectory.

Our hello example was developed using the directory structure mentioned in the Oracle Application Server Containers for J2EE User's Guide. Notice in Figure 2-1 that the EJB and Web modules exist under the `hello` application parent directory and are developed separately in their own directory.

#### Figure 2-1 Hello Directory Structure

Text description of the illustration primer2.gif

Note: For EJB modules, the top of the module (`ejb_module`) represents the start of a search path for classes. As a result, classes belonging to packages are expected to be located in a nested directory structure beneath this point. For example, a reference to a package class '`myapp.Hello.class`' is expected to be located in "`...hello/ejb_module/myapp/Hello.class`".

### Implement the EJB

When you implement a session or entity EJB, create the following:

Note: Message-driven beans have similar, but not the same, requirements as listed below. See Chapter 7, "Message-Driven Beans" for information.

1. The home interfaces for the bean. The home interface defines the `create` method for your bean. If the EJB is an entity bean, it also defines the finder method(s) for that bean.

   1. The remote home interface extends `javax.ejb.EJBHome`.

   2. The local home interface extends `javax.ejb.EJBLocalHome`.

2. The component interfaces for the bean.

   1. The remote interface declares the methods that a client can invoke remotely. It extends `javax.ejb.EJBObject`.

   2. The local interface declares the methods that a collocated bean can invoke locally. It extends `javax.ejb.EJBLocalObject`.

3. The bean implementation includes the following:

   1. The implementation of the business methods that are declared in the component interfaces.

   2. The container callback methods that are inherited from either the `javax.ejb.SessionBean` or `javax.ejb.EntityBean` interfaces.

   3. The `ejb*` methods that match the home interface `create` methods:

      - For stateless session beans, provide an `ejbCreate` method with no parameters.

      - For stateful session beans, provide an `ejbCreate` method with parameters matching those of the create method as defined in the home interfaces.

      - For entity beans, provide `ejbCreate` and `ejbPostCreate` methods with parameters matching those of the `create` method as defined in the home interfaces.

#### Creating the Home Interfaces

The home interfaces (remote and local) are used to create the bean instance; thus, they define the `create` method for your bean. Each type of EJB can define the `create` method in the following ways:

EJB Type | Create Parameters
--- | ---
Stateless Session Bean | Can have only a single `create` method, with no parameters.
Stateful Session Bean | Can have one or more `create` methods, each with its own defined parameters.
Entity Bean | Can have zero or more `create` methods, each with its own defined parameters. All entity beans must define one or more finder methods, where at least one is a `findByPrimaryKey` method.

For each `create` method, a corresponding `ejbCreate` method is defined in the bean implementation.

##### Remote Invocation

Any remote client invokes the EJB through its remote interface. The client invokes the `create` method that is declared within the remote home interface. The container passes the client call to the `ejbCreate` method--with the appropriate parameter signature--within the bean implementation. You can use the parameter arguments to initialize the state of the new EJB object.

1. The remote home interface must extend the `javax.ejb.EJBHome` interface.

2. All `create` methods may throw the following exceptions:

   - `javax.ejb.CreateException`

   - `javax.ejb.EJBException` or another `RuntimeException`

#### Example 2-1 Remote Home Interface for Session Bean

The following code sample illustrates a remote home interface for a stateless session bean called `HelloHome`.

    package hello;

    import javax.ejb.*;
    import java.rmi.*;

    public interface HelloHome extends EJBHome
    {
      public Hello create() throws CreateException, RemoteException;
    }

##### Local Invocation

An EJB can be called locally from a client that exists in the same container. Thus, a collocated bean, JSP, or servlet invokes the `create` method that is declared within the local home interface. The container passes the client call to the `ejbCreate` method--with the appropriate parameter signature--within the bean implementation. You can use the parameter arguments to initialize the state of the new EJB object.

1. The local home interface must extend the `javax.ejb.EJBLocalHome` interface.

2. All `create` methods may throw the following exceptions:

   - `javax.ejb.CreateException`

   - `javax.ejb.EJBException` or another `RuntimeException`

#### Example 2-2 Local Home Interface for Session Bean

The following code sample shows a local home interface for a stateless session bean called `HelloLocalHome`.

    package hello;

    import javax.ejb.*;

    public interface HelloLocalHome extends EJBLocalHome
    {
     public HelloLocal create() throws CreateException, EJBException;
    }

#### Creating the Component Interfaces

The component interfaces define the business methods of the bean that a client can invoke.

##### Creating the Remote Interface

The remote interface defines the business methods that a remote client can invoke. Here are the requirements for developing the remote interface:

1. The remote interface of the bean must extend the `javax.ejb.EJBObject` interface, and its methods must throw the `java.rmi.RemoteException` exception.

2. You must declare the remote interface and its methods as `public` for remote clients.

3. The remote interface, all its method parameters, and return types must be serializable. In general, any object that is passed between the client and the EJB must be serializable, because RMI marshals and unmarshals the object on both ends.

4. Any exception can be thrown to the client, as long as it is serializable. Runtime exceptions, including `EJBException` and `RemoteException`, are transferred back to the client as remote runtime exceptions.

#### Example 2-3 Remote Interface Example for Hello Session Bean

The following code sample shows a remote interface called `Hello` with its defined methods, each of which will be implemented in the stateless session bean.

    package hello;

    import javax.ejb.*;
    import java.rmi.*;

    public interface Hello extends EJBObject
    {
      public String sayHello(String myName) throws RemoteException;
    }

##### Creating the Local Interface

The local interface defines the business methods of the bean that a local (collocated) client can invoke.

1. The local interface of the bean must extend the `javax.ejb.EJBLocalObject` interface.

2. You declare the local interface and its methods as `public`.

#### Example 2-4 Local Interface for Hello Session Bean

The following code sample contains a local interface called `HelloLocal` with its defined methods, each of which will be implemented in the stateless session bean.

    package hello;

    import javax.ejb.*;

    public interface HelloLocal extends EJBLocalObject
    {
      public String sayHello(String myName) throws EJBException;
    }

#### Implementing the Bean

The bean contains the business logic for your application. It implements the following methods:

1. The signature for each of these methods must match the signature in the remote or local interface, except that the bean does not throw the `RemoteException`. Since both the local and the remote interfaces use the bean implementation, the bean implementation cannot throw the `RemoteException`.

2. The lifecycle methods are inherited from the `SessionBean` or `EntityBean` interface. These include the `ejb<Action>` methods, such as `ejbActivate`, `ejbPassivate`, and so on.

3. The `ejbCreate` methods that correspond to the `create` method(s) that are declared in the home interfaces. The container invokes the appropriate `ejbCreate` method when the client invokes the corresponding `create` method.

4. Any methods that are private to the bean or package used for facilitating the business logic. This includes private methods that your public methods use for completing the tasks requested of them.

#### Example 2-5 Hello Stateless Session Bean Implementation

The following code shows the bean implementation for the Hello example.

Note: You can download the stateless session bean example from the OC4J sample code page on the OTN Web site.

    package hello;

    import javax.ejb.*;

    public class HelloBean implements SessionBean
    {
      public SessionContext ctx;

      public HelloBean()
      {    // constructor
      }

      public void ejbCreate() throws CreateException
      {   // when bean is created
      }

      public void ejbActivate()
      {    // when bean is activated
      }

      public void ejbPassivate()
      {    // when bean is deactivated
      }

      public void ejbRemove()
      {   // when bean is removed
      }

      public void setSessionContext(SessionContext ctx)
      {    this.ctx = ctx;
      }

      public void unsetSessionContext()
      {    this.ctx = null;
      }

      public String sayHello(String myName) throws EJBException
      {
        return ("Hello " + myName);
      }
    }

Note: You can download this example on OTN from the OC4J sample code page on the OTN Web site.

### Access the EJB

To access an EJB from a client, you must do the following:

1. If you are remote, download the `oc4j.jar` file.

2. Set up JNDI properties for the connection, if necessary.

3. Determine which `InitialContextFactory` you will use for the connection.

4. Retrieve an EJB using either the JNDI name or an EJB reference, which is configured in the deployment descriptor.

These subjects are discussed in the following sections:

- Client Installation of OC4J.JAR

- How to Lookup the EJB Reference

- Client Implementation to Invoke the EJB

- EJB Reference Information

- Setting JNDI Properties

- Using the Initial Context Factory Classes

- Accessing an EJB in Another Application

- Accessing an EJB in a Remote Server

#### Client Installation of OC4J.JAR

In order to access EJBs, the client-side must download `oc4j_client.zip` file from `http://otn.oracle.com/software/products/ias/devuse.html`. Unzip the JAR into a directory that is in your `CLASSPATH`. This JAR contains the classes necessary for client interaction. If you download this JAR into a browser, you must grant certain permissions. See "Granting Permissions in Browser" for a list of these permissions.

#### How to Lookup the EJB Reference

Before you start implementing your call to the EJB in your client, you should consider the following for the JNDI retrieval of the EJB reference of the bean:

- Within your client code, you retrieve an EJB reference to the target bean in order to execute methods on that bean. Do you want to set up a logical name for the target bean or use the JNDI name?

  - Use the logical name: Modify the client XML configuration file to set up the `<ejb-ref>` element with the target bean information. The logical name specified in the `<ejb-ref-name>` element is used in the JNDI lookup. See "EJB Reference Information" for more information on the `<ejb-ref>` and `<ejb-ref-name>` elements.

  - Use the actual name: The actual name of the bean is used in the JNDI lookup. This name has been specified in the target bean's `ejb-jar.xml` XML deployment descriptors in the `<ejb-name>` element.

- The method for accessing EJBs depends on where your client is located relative to the bean it wants to invoke.

  - Is the client is collocated with the target bean? Deployed in the same application? Or is the target bean part of an application that is this client's parent? You do not need to set up any JNDI properties.

  - Otherwise, you must set up JNDI properties. There are two methods for setting up JNDI properties. See "Setting JNDI Properties" for more information

#### Client Implementation to Invoke the EJB

All EJB clients implement the following steps to instantiate a bean, invoke its methods, and destroy the bean:

1. Look up the home interface through a JNDI lookup. Follow JNDI and the EJB specification conventions for retrieving the bean reference, including setting up JNDI properties if the bean is remote to the client. See "How to Lookup the EJB Reference".

2. Narrow the returned object from the JNDI lookup to the home interface, as follows:

   1. When accessing the remote interface, use the `PortableRemoteObject.narrow` method to narrow the returned object.

   2. When accessing the local interface, cast the returned object with the local home interface type.

3. Create instances of the bean in the server through the returned object. Invoking the `create` method on the home interface causes a new bean to be instantiated and returns a bean reference.

   Note: For entity beans that are already instantiated, you can retrieve the bean reference through one of its finder methods.

4. Invoke business methods, which are defined in the component (remote or local) interface.

5. After you are finished, invoke the `remove` method. This will either remove the bean instance or return it to a pool. The container controls how to act on the `remove` method.

These steps are demonstrated in Example 2-6.

#### Example 2-6 A Servlet Acting as a Local Client

The following example is executed from a servlet that is collocated with the Hello bean. Thus, the session bean uses the local interface, and the JNDI lookup does not require JNDI properties.

Note: The JNDI name is specified in the `<ejb-local-ref>` element in this session bean EJB deployment descriptor as follows: `<ejb-local-ref> <ejb-ref-name>ejb/HelloBean</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <local-home>hello.HelloLocalHome</local-home> <local>hello.HelloLocal</local> </ejb-loca`l-`ref>`

    package hello;

    import javax.servlet.http.*;
    import javax.servlet.*;
    import javax.ejb.*;
    import javax.naming.*;
    import java.io.IOException;

    public class HelloServlet extends HttpServlet
    {
      HelloLocalHome helloHome;
      HelloLocal hello;

      public void init() throws ServletException
      {
        try {
         // 1. Retreive the Home Interface using a JNDI Lookup
         // Retrieve the initial context for JNDI.

         // No properties needed when local
          Context context = new InitialContext();

          // Retrieve the home interface using a JNDI lookup using
          // the java:comp/env bean environment variable

          // specified in web.xml
          helloHome = (HelloLocalHome)

                 context.lookup("java:comp/env/ejb/HelloBean");

         //2. Narrow the returned object to be an HelloHome object.

         // Since the client is local, cast it to the correct object type.
         //3. Create the local Hello bean instance, return the reference
          hello = (HelloLocal)helloHome.create();

        } catch(NamingException e) {
          throw new ServletException("Error looking up home", e);
        } catch(CreateException e) {
          throw new ServletException("Error creating local hello bean", e);
        }
      }

      public void doGet(HttpServletRequest request,

                          HttpServletResponse response)
        throws ServletException, IOException
      {
        response.setContentType("text/html");
        ServletOutputStream out = response.getOutputStream();
        try
        {
          out.println("<html>");
          out.println("<body>");
         //4. Invoke a business method on the local interface reference.
          out.println(hello.sayHello("James Earl"));
          out.println("</body>");
          out.println("</html>");
        } catch(EJBException e) {
          out.println("EJBException error: " + e.getMessage());
        } catch(IOException e) {
          out.println("IOException error: " + e.getMessage());
        } finally {
          out.close();
        }
      }
    }

Note:: You can download this example on OTN from the OC4J sample code page on the OTN Web site.

#### Example 2-7 A Java Client as a Remote Client

The following example is executed from a pure Java client that is a remote client. Any remote client must set up JNDI properties before retrieving the object, using a JNDI lookup.

Note: The JNDI name is specified in the `<ejb-ref>` element in the this client's `application-client.xml` file--as follows: `<ejb-ref> <ejb-ref-name>ejb/HelloBean</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <home>hello.HelloHome</home> <remote>hello.Hello</remote> </ejb-ref>`

The `jndi.properties` file for this client is as follows:

    java.naming.factory.initial=

            com.evermind.server.ApplicationClientInitialContextFactory
    java.naming.provider.url=opmn:ormi://opmnhost:oc4j_inst1/helloworld
    java.naming.security.principal=admin
    java.naming.security.credentials=welcome

The pure Java client that invokes `Hello` remotely is as follows:

    package hello;

    import javax.ejb.*;
    import javax.naming.*;
    import javax.rmi.PortableRemoteObject;
    import java.io.*;
    import java.util.*;
    import java.rmi.RemoteException;

    /*
     * A simple client for accessing an EJB.
     */

    public class HelloClient
    {
      public static void main(String[] args)
      {
        System.out.println("client started...");
        try {
          // Initial context properties are set in the jndi.properties file
          //1. Retrieve remote interface using a JNDI lookup*/
          Context context = new InitialContext();

         // Lookup the HelloHome object. The reference is retrieved from the
         // application-local context (java:comp/env). The variable is
         // specified in the application-client.xml).
          Object homeObject = context.lookup("java:comp/env/Helloworld");

         //2. Narrow the reference to HelloHome. Since this is a remote

         //   object, use the PortableRemoteObject.narrow method.
          HelloHome home = (HelloHome) PortableRemoteObject.narrow

                                            (homeObject, HelloHome.class);

         //3. Create the remote object and narrow the reference to Hello.
          Hello remote =
            (Hello) PortableRemoteObject.narrow(home.create(), Hello.class);

         //4. Invoke a business method on the remote interface reference.
          System.out.println(remote.sayHello("James Earl"));

        } catch(NamingException e) {
          System.err.println("NamingException: " + e.getMessage());
        } catch(RemoteException e) {
          System.err.println("RemoteException: " + e.getMessage());
        } catch(CreateException e) {
          System.err.println("FinderException: " + e.getMessage());
        }
      }
    }

Note: You can download this example on OTN from the OC4J sample code page on the OTN Web site.

#### EJB Reference Information

Specify the EJB reference information for the remote EJB in the `<ejb-ref>` or `<ejb-local-ref>` elements in the client's XML file:

- `application-client.xml`: The client is a pure-Java client, invoking the bean outside of the container.

- `ejb-jar.xml`: The client is another EJB.

- `web.xml`: The client is a servlet or JSP.

A full description or how to set up the `<ejb-ref>` element is given in "Configuring Environment References".

For example, if a client wants to access the remote interface of the `Hello` example, then the client's XML would define the following:

    <ejb-ref>
    	<ejb-ref-name>ejb/HelloBean</ejb-ref-name>
    	<ejb-ref-type>Session</ejb-ref-type>
    	<home>hello.HelloHome</home>
    	<remote>hello.Hello</remote>
    </ejb-ref>

If the client wants to access the local interface of the `Hello` example, then the client's XML would define the following:

    <ejb-ref>
    	<ejb-ref-name>ejb/HelloBean</ejb-ref-name>
    	<ejb-ref-type>Session</ejb-ref-type>
    	<local-home>hello.HelloLocalHome</local-home>
    	<local>hello.HelloLocal</local>
    </ejb-ref>

OC4J maps the logical name to the actual JNDI name on the client-side. The server-side receives the JNDI name and resolves it within its JNDI tree.

#### Setting JNDI Properties

If the client is collocated with the target, the client exists within the same application as the target, or the target exists within its parent, then you do not need a JNDI properties file. Else, you must initialize your JNDI properties either within a `jndi.properties` file, in the system properties, or within your implementation, before the JNDI call. The following sections discuss these three options:

- No JNDI Properties

- JNDI Properties File

- JNDI Properties Within The Implementation

- JNDI Properties for OC4J Standalone

To specify credentials within the JNDI properties, see "Specifying Credentials in EJB Clients".

Note: A full description of how to use JNDI, see the JNDI chapter in the Oracle Application Server Containers for J2EE Services Guide.

##### No JNDI Properties

A servlet that is collocated with the target bean automatically accesses the JNDI properties for the node. Thus, accessing the EJB is simple: no JNDI properties are required.

    //Get the Initial Context for the JNDI lookup for a local EJB
    InitialContext ic = new InitialContext();
    //Retrieve the Home interface using JNDI lookup
    Object helloObject = ic.lookup("java:comp/env/ejb/HelloBean");

This is also true if the target bean is in the same application or an application that has been deployed as this application's parent. See the Oracle Application Server Containers for J2EE User's Guide for more information on how to set the parent of the application.

##### JNDI Properties File

If setting the JNDI properties within the `jndi.properties` file, set the properties as follows. Make sure that this file is accessible from the `CLASSPATH`.

##### Factory

See "Using the Initial Context Factory Classes" for discussion on the initial context factory to use.

    java.naming.factory.initial=

    	com.evermind.server.ApplicationClientInitialContextFactory

##### Location

All ports, including the RMI port, are dynamically set by OPMN when each OC4J instance starts. When you specify the following URL in the client JNDI properties, the client-side OC4J retrieves the dynamic ports for the instance, and chooses one from the list for communication.

    java.naming.provider.url=

      opmn:ormi://<opmn_host>:<opmn_port>:<oc4j_instance>/<application-name>

The OPMN host name and port number is retrieved from the `opmn.xml` file. In most cases, OPMN is located on the same machine as the OC4J instance. However, you must specify the host name in case it is located on another machine. The OPMN port number is optional; if excluded, the default is port 6003. The OPMN port is specified in `opmn.xml`.

The OC4J instance name is defined in the Oracle Enterprise Manager.

##### Security

When you access EJBs in a remote container, you must pass valid credentials to this container. Stand-alone clients define their credentials in the `jndi.properties` file deployed with the client's code.

    java.naming.security.principal=<username>
    java.naming.security.credentials=<password>

##### JNDI Properties Within The Implementation

Set the properties with the same values, only with a different syntax. For example, JavaBeans running within the container pass their credentials within the `InitialContext`, which is created to look up the remote EJBs.

- In the `java.naming.provider.url`, the "`opmn:ormi`" location string is provided. Both OPMN and OC4J are located on the same host. The OPMN default port is used, so the port number is not specified.

- In the `java.naming.factory.initial`, the `ApplicationClientInitialContextFactory` object is used.

To pass JNDI properties within the `Hashtable` environment, set these as shown below:

    Hashtable env = new Hashtable();
    env.put("java.naming.provider.url",
           "opmn:ormi://opmnhost:oc4j_inst1/ejbsamples");
    env.put("java.naming.factory.initial",
          "com.evermind.server.ApplicationClientInitialContextFactory");
    env.put(Context.SECURITY_PRINCIPAL, "guest");
    env.put(Context.SECURITY_CREDENTIALS, "welcome");
    Context ic = new InitialContext (env);
    Object homeObject = ic.lookup("java:comp/env/ejb/HelloBean");

    // Narrow the reference to a HelloHome.
    HelloHome empHome =
    	 (HelloHome) PortableRemoteObject.narrow(homeObject,
                                                       HelloHome.class);

##### JNDI Properties for OC4J Standalone

The rules for which initial context factory are the same for OC4J standalone applications. However, since OC4J standalone does not use OPMN, the location URL cannot use the `opmn:ormi://` prefix. Instead, the `ormi://` prefix is used.

The ORMI default port number is 23791, which can be modified in `config/rmi.xml`. Thus, set the URL in the `jndi.properties`, in one of the two ways:

    java.naming.provider.url=ormi://<hostname>/<application-name>

or

    java.naming.provider.url=ormi://<hostname>:23791/<application-name>\

When you access EJBs in a remote container, you must pass valid credentials to this container. Stand-alone clients define their credentials in the `jndi.properties` file deployed with the client's code.

    java.naming.security.principal=<username>
    java.naming.security.credentials=<password>

If you set the properties within the bean implementation, then set them with the same values, just with different syntax. For example, JavaBeans running within the container pass their credentials within the `InitialContext`, which is created to look up the remote EJBs.

To pass JNDI properties within the `Hashtable` environment, set these as shown below:

    Hashtable env = new Hashtable();
    env.put("java.naming.provider.url", "ormi://myhost/ejbsamples");
    env.put("java.naming.factory.initial",
           "com.evermind.server.ApplicationClientInitialContextFactory");
    env.put(Context.SECURITY_PRINCIPAL, "guest");
    env.put(Context.SECURITY_CREDENTIALS, "welcome");
    Context ic = new InitialContext (env);
    Object homeObject = ic.lookup("java:comp/env/ejb/HelloBean");

    // Narrow the reference to a HelloHome.
    HelloHome helloHome =
      (HelloHome) PortableRemoteObject.narrow(homeObject,
                                                        HelloHome.class);

#### Using the Initial Context Factory Classes

The type of initial context factory that you use depends on who the client is. The initial context factory creates the initial context class for the client.

- If the client is a pure Java client outside of the OC4J container, use the `ApplicationClientInitialContextFactory` class.

- If the client is an EJB or servlet client within the OC4J container, use the `ApplicationInitialContextFactory` class. The `ApplicationInitialContextFactory` class is the default class; thus, each time you create a new `InitialContext` without specifying any initial context factory class, your client uses the `ApplicationInitialContextFactory` class.

- If the client is an administrative class that is going to manipulate or traverse the JNDI tree, use the `com.evermind.server.RMIInitialContextFactory` class.

- If the client is going to use DNS load balancing, use the `RMIInitialContextFactory` class.

For example, if you have a pure Java client, then you set the initial context factory class ("java.naming.factory.initial") to `ApplicationClientInitialContextFactory`. The following example sets the initial context factory in the environment, but you could also put this in the JNDI properties file.

    env.put("java.naming.factory.initial",
          "com.evermind.server.ApplicationClientInitialContextFactory");

If the client is an EJB or a servlet calling an EJB in the same application, you can use the default by not setting the JNDI properties with a initial context factory and uses the `ApplicationInitialContextFactory` object by executing the following:

    InitialContext ic = new InitialContext();

If you decide to use the `RMIInitialContextFactory` class, you must use the JNDI name in the lookup and not a logical name defined in the `<ejb-ref>` in your XML configuration file.

##### An Initial Context Factory Specific to DNS Load Balancing

To use DNS for load balancing, you must do the following:

1. Within DNS, map a single host name to several IP addresses. Each of the port numbers must be the same for each IP address. Set up the DNS server to return the addresses either in a round-robin or random fashion.

2. Turn off DNS caching on the client. For UNIX machines, you must turn off DNS caching as follows:

   1. Kill the NSCD daemon process on the client.

   2. Start the OC4J client with the `-Dsun.net.inetaddr.ttl=0` option.

3. Within each client, use any initial context factory to create an initial context. You can use either the `opmn:ormi://` or the `ormi://` prefix in the provider URL. Use `opmn:ormi://` syntax for Oracle Application Server applications and the `ormi://` for standalone OC4J applications.

4. Set the `dedicated.rmicontext` property to true.

Each time the lookup occurs on the DNS server, the DNS server hands back a one of the many IP addresses that are mapped to it.

#### Example 2-8 RMIInitialContextFactory Example

    java.naming.factory.initial=
               com.evermind.server.rmi.RMIInitialContextFactory
    java.naming.provider.url=opmn:ormi://myserver:oc4j_inst/applname
    java.naming.security.principal=admin
    java.naming.security.credentials=welcome
    dedicated.rmicontext=true

#### Accessing an EJB in Another Application

Normally, you cannot have EJBs communicating across EAR files, that is, across applications that are deployed in separate EAR files. The only way for an EJB to access an EJB that was deployed in a separate EAR file is to declare it to be the parent of the client. Only children can invoke methods in a parent.

For example, there are two EJBs, each deployed within their EAR file, called `sales` and `inventory`, where the `sales` EJB needs to invoke the `inventory` EJB to check to see if enough widgets are available. Unless the `sales` EJB defines the `inventory` EJB to be its parent, the `sales` EJB cannot invoke any mehtods in the `inventory` EJB, because they are both deployed in separate EAR files. So, define the `inventory` EJB to be the parent of the `sales` EJB and the `sales` EJB can now invoke any method in its parent.

You can only define the parent during deployment with the deployment wizard. See the "Deploying Applications" section in the "Configuration and Deployment" chapter in Oracle Application Server Containers for J2EE User's Guide on how to define the parent application of a bean. For broader issues on how to package your classes for method invocation, see "Sharing Classes".

#### Accessing an EJB in a Remote Server

A multi-tier situation exists when you have the servlets executing in one server which are to connect and communicate with EJBs in another server. Both the servlets and EJBs are contained in the same application. When you deploy the application to two different servers, the servlets normally look for the local EJB first.

In Figure 2-2, the `Hello`Bean application is deployed to both server 1 and 2. In order to ensure that the servlets only call out from server 1 to the EJBs in server 2, you must set the `remote` attribute appropriately in the application before deploying on both servers.

#### Figure 2-2 Multi-Tier Example

Text description of the illustration o_1046.gif

The `remote` attribute in the `<ejb-module>` element in `orion-application.xml` for the EJB module denotes whether the EJBs for this application are deployed or not.

1. In server 1, you must set `remote=true` in the `<ejb-module>` element of the `orion-application.xml` file and then deploy the application. The EJB module within the application will not be deployed. Thus, the servlets will not look for the EJBs locally, but will go out to the remote server for the EJB requests.

2. In server 2, you must set `remote=false` in the `<ejb-module>` element of the `orion-application.xml` file and then deploy the application. The application, including the EJB module, is deployed as normal. The default for the `remote` attribute is false; thus, simply ensure that the `remote` attribute is not true and redeploy the application.

3. In the `<server>` element of the `rmi.xml` file of server 1, configure the location of server 2, which is the remote server. Provide the hostname, port number, username, and password of the remote server, as follows:

       <server host=<remote_host> port=<remote_port> username=<username>
       password=<password> />

If multiple remote servers are configured, the OC4J container searches all remote servers for the intended EJB application.

#### Example 2-9 Servlet Accessing EJB in Remote OC4J Instance

The following servlet uses the JNDI name for the target bean: `HelloBean`. This servlet provides the JNDI properties in an `RMIInitialContext` object. The environment is initialized as follows:

- The `INITIAL_CONTEXT_FACTORY` is initialized to a `RMIInitialContextFactory`.

- Instead of creating a new `InitialContext`, it is retrieved.

- The actual JNDI name is used in the lookup.

- The remote location URL is
  `opmn:ormi://host:oc4j_inst/application`". The OPMN port number uses the default and is omitted.

      Hashtable env = new Hashtable();
      env.put(Context.PROVIDER_URL, "opmn:ormi://theirhost:oc4j_inst/myapp");
      env.put(Context.SECURITY_PRINCIPAL, "admin");
      env.put(Context.SECURITY_CREDENTIALS, "welcome");
      env.put(Context.INITIAL_CONTEXT_FACTORY,
      	"com.evermind.server.rmi.RMIInitialContextFactory");

      Context ic =

      	new com.evermind.server.rmi.RMIInitialContextFactory().

      		getInitialContext(env);

      Object homeObject = ic.lookup("ejb/HelloBean");

      // Narrow the reference to a HelloHome.
      HelloHome helloHome =
      	 (HelloHome) PortableRemoteObject.narrow(homeObject,
                                                         HelloHome.class);

### Create the Deployment Descriptor

After implementing and compiling your classes, you must create the standard J2EE EJB deployment descriptor for all beans in the module. The XML deployment descriptor (defined in the `ejb-jar.xml` file) describes the EJB module of the application. It describes the types of beans, their names, and attributes. The structure for this file is mandated in the DTD file, which is provided at " http://java.sun.com/dtd/ejb-jar_2_0.dtd".

Any EJB container services that you want to configure is also designated in the deployment descriptor. For information about data sources and JTA, see the Oracle Application Server Containers for J2EE Services Guide. For information about security, see the Oracle Application Server Containers for J2EE Security Guide..

After creation, place the deployment descriptors for the EJB application in the `META-INF` directory that is located in the same directory as the EJB classes. See Figure 2-1 for more information.

The following example shows the sections that are necessary for the `Hello` example, which implements both a remote and a local interface.

#### Example 2-10 XML Deployment Descriptor for Hello Bean

The following is the deployment descriptor for a version of the Hello example that uses a stateless session bean. This example defines both the local and remote interfaces. You do not have to define both interface types; you may define only one of them.

    <?xml version="1.0"?>
    <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise
    JavaBeans 1.1//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">

    <ejb-jar>
       <display-name>hello</display-name>
       <description>
          An EJB app containing only one Stateless Session Bean
       </description>
       <enterprise-beans>
          <session>
             <description>no description</description>
             <display-name>HelloBean</display-name>
             <ejb-name>HelloBean</ejb-name>
             <home>hello.HelloHome</home>
             <remote>hello.Hello</remote>
             <local-home>hello.HelloLocalHome</local-home>
             <local>hello.HelloLocal</local>
             <ejb-class>hello.HelloBean</ejb-class>
             <session-type>Stateless</session-type>
             <transaction-type>Container</transaction-type>
          </session>
       </enterprise-beans>

       <assembly-descriptor>
          <container-transaction>
             <method>
                <ejb-name>HelloBean</ejb-name>
                <method-name>*</method-name>
             </method>
             <trans-attribute>Supports</trans-attribute>
          </container-transaction>
          <security-role>
             <role-name>users</role-name>
          </security-role>
       </assembly-descriptor>
    </ejb-jar>

Note: You can download this example on OTN from the OC4J sample code page on the OTN Web site.

### Archive the EJB Application

After you have finalized your implementation and created the deployment descriptors, archive your EJB application into a JAR file. The JAR file should include all EJB application files and the deployment descriptor.

Note: If you have included a Web application as part of this enterprise Java application, follow the instructions for building the Web application in the Oracle Application Server Containers for J2EE User's Guide.

For example, to archive your compiled EJB class files and XML files for the `Hello` example into a JAR file, perform the following in the `../hello/ejb_module` directory:

    % jar cvf helloworld-ejb.jar .

This archives all files contained within the `ejb_module` subdirectory within the JAR file.

## Prepare the EJB Application for Assembly

To prepare the application for deployment, you do the following:

1. Modify the `application.xml` file with the modules of the enterprise Java application.

2. Archive all elements of the application into an EAR file.

These steps are described in the following sections:

- Modify the Application.XML File

- Create the EAR File

### Modify the Application.XML File

The `application.xml` file acts as the manifest file for the application and contains a list of the modules that are included within your enterprise application. You use each `<module>` element defined in the `application.xml` file to designate what comprises your enterprise application. Each module describes one of three things: EJB JAR, Web WAR, or any client files. Respectively, designate the `<ejb>`, `<web>`, and `<java>` elements in separate `<module>` elements.

- The `<ejb>` element specifies the EJB JAR filename.

- The `<web>` element specifies the Web WAR filename in the `<web-uri>` element, and its context in the `<context>` element.

- The `<java>` element specifies the client JAR filename, if any.

As Figure 2-3 shows, the `application.xml` file is located under a `META-INF` directory under the parent directory for the application. The JAR, WAR, and client JAR files should be contained within this directory. Because of this proximity, the `application.xml` file refers to the JAR and WAR files only by name and relative path--not by full directory path. If these files were located in subdirectories under the parent directory, then these subdirectories must be specified in addition to the filename.

#### Figure 2-3 Archive Directory Format

Text description of the illustration primer3.gif

For example, the following example modifies the `<ejb>`, `<web>`, and `<java>` module elements within `application.xml` for the Hello EJB application that also contains a servlet that interacts with the EJB.

    <?xml version="1.0"?>
    <!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE
    Application 1.2//EN" "http://java.sun.com/j2ee/dtds/application_1_
    2.dtd">
    <application>
      <display-name>helloworld j2ee application</display-name>
      <description>
         A sample J2EE application that uses a Helloworld Session Bean
         on the server and calls from java/servlet/JSP clients.
      </description>
      <module>
        <ejb>helloworld-ejb.jar</ejb>
      </module>
      <module>
        <web>
          <web-uri>helloworld-web.war</web-uri>
          <context-root>/helloworld</context-root>
        </web>
      </module>
      <module>
        <java>helloworld-client.jar</java>
      </module>
    </application>

### Create the EAR File

Create the EAR file that contains the JAR, WAR, and XML files for the application. Note that the `application.xml` file serves as the EAR manifest file.

To create the `helloworld.ear` file, execute the following in the `hello` directory contained in Figure 2-3:

    % jar cvf helloworld.ear .

This step archives the `application.xml`, the `helloworld-ejb.jar`, the `helloworld-web.war`, and the `helloworld-client.jar` files into the `helloworld.ear` file.

## Deploy the Enterprise Application to OC4J

After archiving your application into an EAR file, deploy the application to OC4J. See the Oracle Application Server Containers for J2EE User's Guide for information on how to deploy your application.

| Copyright © 2002, 2003 Oracle Corporation. All Rights Reserved. |
Home | Contents | Index