Skip Headers

Oracle9iAS Containers for J2EE User's Guide
Release 2 (9.0.3)

Part Number A97681-01
Go To Core Documentation
Core
Go To Platform Documentation
Platform
Go To Table Of Contents
Contents
Go To Index
Index

Go to previous page Go to next page

7
EJB Primer

After you have installed Oracle9iAS 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.

This chapter demonstrates simple EJB development with a basic OC4J-specific configuration and deployment. Download the stateless session bean example (stateless.jar) from the OC4J sample code page on the OTN Web site.

To develop and deploy EJB applications with OC4J, do the following:

For more information on EJBs in OC4J, see Oracle9iAS Containers for J2EE Enterprise JavaBeans Developer's Guide and Reference.

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 7-1 shows).

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

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

  4. 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 employee example was developed using the directory structure mentioned in "Creating the Development Directory". Notice in Figure 7-1 that the EJB and Web modules exist under the employee application parent directory and are developed separately in their own directory.

Figure 7-1 Employee Directory Structure

Text description of ejbprima.gif follows

Text description of the illustration ejbprima.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.Employee.class' is expected to be located in "...employee/ejb_module/myapp/Employee.class".


Implement the EJB

When you implement an EJB, create the following:

  1. The home interfaces for the bean. The home interface defines the create method for your bean. If the bean 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 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 must throw the following exceptions:

    • javax.ejb.CreateException

    • either java.rmi.RemoteException or javax.ejb.EJBException

Example 7-1 Remote Home Interface for Session Bean

The following code sample illustrates a remote home interface for a session bean called EmployeeHome.

package employee;

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

public interface EmployeeHome extends EJBHome
{
  public Employee 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 must throw the following exceptions:

    • javax.ejb.CreateException

    • javax.ejb.EJBException

Example 7-2 Local Home Interface for Session Bean

The following code sample shows a local home interface for a session bean called EmployeeLocalHome.

package employee;

import javax.ejb.*;

public interface EmployeeLocalHome extends EJBLocalHome
{
    public EmployeeLocal 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 7-3 Remote Interface Example for Employee Session Bean

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

package employee;

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

public interface Employee extends EJBObject
{
  public Collection getEmployees()
    throws RemoteException;

  public EmpRecord getEmployee(Integer empNo)
    throws RemoteException;

  public void setEmployee(Integer empNo, String empName, Float salary)
    throws RemoteException;

  public EmpRecord addEmployee(Integer empNo, String empName,
Float salary) throws RemoteException; public void removeEmployee(Integer empNo) 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 7-4 Local Interface for Employee Session Bean

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

package employee;

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

public interface EmployeeLocal extends EJBLocalObject
{
  public Collection getEmployees() throws EJBException;

  public EmpRecord getEmployee(Integer empNo)
    throws FinderException, EJBException;

  public void setEmployee(Integer empNo, String empName, Float salary)
    throws FinderException, EJBException;

  public EmpRecord addEmployee(Integer empNo, String empName,
     Float salary) throws CreateException, EJBException;

  public void removeEmployee(Integer empNo)
    throws RemoveException, 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.

    The bean in the example application consists of one class, EmployeeBean, that retrieves an employee's information.

  2. The methods defined in the home interfaces are inherited from the SessionBean or EntityBean interface. The container uses these methods for controlling the life cycle of the bean. 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 7-5 Employee Session Bean Implementation

The following code shows the bean implementation for the employee example. To compact this example, the try blocks for error processing are removed. See the full example on http://otn.oracle.com.

package employee;

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

public class EmployeeBean extends Object implements SessionBean
{
  public SessionContext ctx;
  public EmployeeLocal empLocal;

  public EmployeeBean() {}

  public EmpRecord addEmployee(Integer empNo, String empName, 
Float salary) throws CreateException { return empLocal.addEmployee(empNo, empName, salary); } public Collection getEmployees() { return empLocal.getEmployees(); } public EmpRecord getEmployee(Integer empNo) throws FinderException { return empLocal.getEmployee(empNo); } public void setEmployee(Integer empNo, String empName, Float salary) throws FinderException { empLocal.setEmployee(empNo, empName, salary); } public void removeEmployee(Integer empNo) throws RemoveException { empLocal.removeEmployee(empNo); } public void ejbCreate() throws CreateException { // stateless bean has create method with no args. This // causes one bean instance to which multiple employees cling. } public void ejbRemove() { empLocal = null; } public void ejbActivate() { } public void ejbPassivate() { } public void setSessionContext(SessionContext ctx) throws EJBException { this.ctx = ctx; Context context = new InitialContext(); /*Lookup the EmployeeLocalHome object. The reference is retrieved from the application-local context (java:comp/env). The variable is specified in the assembly descriptor (META-INF/ejb-jar.xml). */ Object homeObject = context.lookup("java:comp/env/EmployeeLocalBean"); // Narrow the reference to EmployeeHome. EmployeeLocalHome home = (EmployeeLocalHome) homeObject; // Create remote object and narrow the reference to Employee. empLocal = (EmployeeLocal) home.create(); } public void unsetSessionContext() { this.ctx = null; } }

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".

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 7-1 for more information.

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

Example 7-6 XML Deployment Descriptor for Employee Bean

The following is the deployment descriptor for a version of the employee example that uses a stateless session bean.

<?xml version="1.0" encoding="UTF-8"?>
<!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>
         <description>Session Bean Employee Example</description>
         <ejb-name>EmployeeBean</ejb-name>
         <home>employee.EmployeeHome</home>
         <remote>employee.Employee</remote>
         <local-home>employee.EmployeeLocalHome</local-home>
         <local>employee.EmployeeLocal</local>
         <ejb-class>employee.EmployeeBean</ejb-class>
         <session-type>Stateless</session-type>
         <transaction-type>Bean</transaction-type>
      </session>
   </enterprise-beans>
</ejb-jar>

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 Oracle9iAS Containers for J2EE User's Guide.


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

% jar cvf Employee-ejb.jar .

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

Prepare the EJB Application for Assembly

Before deploying, perform 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.

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.

As Figure 7-2 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 7-2 Archive Directory Format

Text description of ejbprim2.gif follows

Text description of the illustration ejbprim2.gif

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

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE 
Application 1.3//EN" "http://java.sun.com/dtd/application_1_3.dtd">
<application>
 <module>
    <ejb>Employee-ejb.jar</ejb>
 </module>
 <module>
  <web>
    <web-uri>Employee-web.war</web-uri>
    <context-root>/employee</context-root>
  </web>
 </module>
 <module>
    <java>Employee-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 Employee.EAR file, execute the following in the employee directory contained in Figure 7-2:

% jar cvf Employee.ear . 

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

Deploy the Enterprise Application to OC4J

After archiving your application into an EAR file, deploy the application to OC4J. See "Deploying Applications" for information on how to deploy your application.

Access the EJB

All EJB clients--including standalone clients, servlets, JSPs, and JavaBeans--perform the following steps to instantiate a bean, invoke its methods, and destroy the bean:

  1. Look up the home interface through a JNDI lookup, which is used for the life cycle management. Follow JNDI conventions for retrieving the bean reference, including setting up JNDI properties if the bean is remote to the client.

  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.

Example 7-7 A Servlet Acting as a Remote Client

The following example is executed from a servlet that acts as 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 client's application-client.xml file--as follows:

<ejb-ref>
<ejb-ref-name>EmployeeBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>employee.EmployeeHome</home>
<remote>employee.Employee</remote>
</ejb-ref>


This code should be executed within a TRY block for catching errors, but the TRY block was removed to show the logic clearly. See the example for the full exception coverage.

public class EmployeeServlet extends HttpServlet
{
  EmployeeHome home;
  Employee empBean;

  public void init() throws ServletException
  {
   /* initialize JNDI context by setting factory, url, and credentials
       in a hashtable */
   Hashtable env = new Hashtable();
   env.put(Context.INITIAL_CONTEXT_FACTORY,    
"com.evermind.server.rmi.ApplicationClientInitialContextFactory"); env.put(Context.PROVIDER_URL, "ormi://myhost/employee"); env.put(Context.SECURITY_PRINCIPAL, "admin"); env.put(Context.SECURITY_CREDENTIALS, "welcome"); /*1. Retrieve remote interface using a JNDI lookup*/ Context context = new InitialContext(); /** * Lookup the EmployeeHome 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/EmployeeBean"); //2. Narrow the reference to EmployeeHome. Since this is a remote
// object, use the PortableRemoteObject.narrow method. EmployeeHome home = (EmployeeHome)
PortableRemoteObject.narrow(homeObject, EmployeeHome.class); //3. Create the remote object and narrow the reference to Employee. Employee empBean = (Employee)
PortableRemoteObject.narrow(home.create(), Employee.class); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); ServletOutputStream out = response.getOutputStream(); //4. Invoke a business method on the remote interface reference. Collection emps = empBean.getEmployees(); out.println("<html>"); out.println( "<head><title>Employee Bean</title></head>"); out.println( "<body>"); out.println( "<table border='2'>"); out.println( "<tr><td>" + "<b>EmployeeNo</b>" + "</td><td>" + "<b>EmployeeName</b>" + "</td><td>" + "<b>Salary</b>" + "</td></tr>"); Iterator iterator = emps.iterator(); while(iterator.hasNext()) { EmpRecord emp = (EmpRecord)iterator.next(); out.println( "<tr><td>" + emp.getEmpNo() + "</td><td>" + emp.getEmpName() + "</td><td>" + emp.getSalary() + "</td></tr>"); } out.println( "</table>"); out.println( "</body>"); out.println("</html>"); out.close(); } }

Example 7-8 A Session Bean Acting as a Local Client

The following example is executed from a session bean that is collocated with the Employee 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-ref> element in the session bean EJB deployment descriptor as follows:

<ejb-local-ref>
<ejb-ref-name>EmployeeLocalBean
</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local-home>employee.EmployeeLocalHome
</local-home>
<local>employee.EmployeeLocal</local>
</ejb-loca
l-ref>


This code should be executed within a TRY block for catching errors, but the TRY block was removed to show the logic clearly. See the example for the full exception coverage.

// 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
Object homeObject = context.lookup("java:comp/env/EmployeeLocalBean");
    
//2. Narrow the returned object to be an EmployeeHome object. Since
//   the client is local, cast it to the correct object type.
EmployeeLocalHome home = (EmployeeLocalHome) homeObject;

//3. Create the local Employee bean instance, return the reference 
Employee empBean = (Employee) home.create();

//4. Invoke a business method on the local interface reference.
Collection emps = empBean.getEmployees();
...


Go to previous page Go to next page
Oracle
Copyright © 2002 Oracle Corporation.

All Rights Reserved.
Go To Core Documentation
Core
Go To Platform Documentation
Platform
Go To Table Of Contents
Contents
Go To Index
Index