Oracle9iAS Release 2 Containers for J2EE

Date: 06/27/02

How-To: Implement Local Interfaces

After completing this how-to you should be able to:

Software Requirements

Notation

Introduction

Entity EJBs in the EJB 1.1 specification were fairly simple representations of business objects in a storage mechanism, usually a database. There was no defined standard for defining relationships, finder methods or local beans (as opposed to assuming every bean is a potentially remote object). Container providers therefore created these features in their containers. Each container implemented these features in different ways, so making the process of moving applications from one vendor to another more difficult.

Recognizing this, the EJB 2.0 specification more clearly defines the roles of entity beans. This includes standard query definition (EJB QL), local interfaces and abstract classes. This article will focus on Local Interfaces in CMP beans.

Remote Beans

The EJB 1.1 specification defines all EJBs as remote objects. This means that every time you make a call to an EJB, you are making a remote call. This means that there is considerable overhead to each EJB call, and hence performance implications. To combat this, server vendors invented a way of circumventing the remote calls to some degree. Oracle's solution with OC4J was the pass-by-reference setting, which determined whether EJB objects were communicated by reference to the object, or whether the whole object had to be passed to the client.

An EJB has a remote interface and a home interface, with the exception of MessageDrivenBeans. The remote interface extends the interface javax.ejb.EJBObject and the home interface extends the interface javax.ejb.EJBHome. The EJB is accessible from any client, in any JVM, provided they have the proper authorization.

For example, the Home and Remote interfaces of an EJB called EMP may look like this.

Remote:

  public interface Emp extends EJBObject
  {
     long getEmpno() throws RemoteException;
     void setEmpno(long newDeptno) throws RemoteException;
     String getEname() throws RemoteException;
     void setEname(String newDname) throws RemoteException;

Home:

  public interface DeptHome extends EJBHome
  {
     public Emp create() throws RemoteException, CreateException;
     public Dept findByPrimaryKey(DeptPK primaryKey) throws RemoteException, FinderException;

Note that both the home and the remote interface throw a RemoteException in all of their method definitions. The ejb-jar.xml deployment descriptor for these EJBs would look something like the snippets below:

  <entity>
    <ejb-name>Emp</ejb-name>
    <home>ejb.cmplocal.EmpHome</home>
    <remote>ejb.cmplocal.Emp</remote>
    <ejb-class>ejb.cmplocal.EmpBean</ejb-class>
    .
    .
    .

Local Beans

The EJB 2.0 specification standardize a means of making local connections to EJBs with Local Interfaces.

For an EJB to be classed as a local EJB, it must implement the local versions of the home and remote interfaces, javax.ejb.EJBLocalObject for the Home interface, and javax.ejb.EJBLocalHome. For a client to call the Local interface, they must be running in the same JVM as the JVM that the EJB exists in. This means that not only an EJB can call a local EJB , Servlets or JSPs can also call the EJB via it's local interface if they are packaged together as part of same application.

For example, the LocalHome and Local interfaces of an EJB called EMP may look like this.

Local:

  public interface Emp extends EJBLocalObject
  {
     long getEmpno();
     void setEmpno(long newEmpno);
     String getEname();
     void setEname(String newEname);

LocalHome:

  public interface EmpHome extends EJBLocalHome
  {
     public Emp create() throws CreateException;
     public Emp findByPrimaryKey(EmpPK primaryKey) throws FinderException;

The ejb-jar.xml deployment descriptor for these EJBs would look something like the snippets below:

  <entity>
    <ejb-name>Emp</ejb-name>
    <local-home>ejb.cmplocal.EmpHome</local-home>
    <local>ejb.cmplocal.Emp</local>
    <ejb-class>ejb.cmplocal.EmpBean</ejb-class>
    <cmp-version>2.x</cmp-version>
    <abstract-schema-name>Emp</abstract-schema-name>

    .
    .
    .

Note that now the local interfaces no longer throw the RemoteException, showing that they are not remotely called methods. Also, the XML contains different elements. There is now a local-home and a local tag. Also we are declaring that this is an EJB 2.x bean, using the cmp-version tag.

Calling Local Beans

Calling a local bean from Java code is very simple, and very similar to using a remote bean. The code to call a remote bean is shown below.

  try
  {
    Context ctx = new InitialContext();
    Object o = ctx.lookup("Emp");
    EmpHome empHome = PortableRemoteObject.narrow(o, EmpHome.class)
    return empHome.findByDeptno(getDeptno());
  }
  catch (RemoteException r)
  {
    System.err.println("Error loading Employees(Remote): " + r.getMessage()); return null;
  }
  catch (NamingException n)
  {
    System.err.println("Error loading Employees(Naming): " + n.getMessage());
    return null;
  }
  catch (FinderException f)
  {
    System.err.println("Error loading Employees(Finder): " + f.getMessage());
    return null;
  }

The code for a local bean is similar, but we no longer have to worry about the PortableRemoteObject, as the bean is no longer remote.

  try
  {
    Context ctx = new InitialContext();
    Object o = ctx.lookup("java:comp/env/LocalEmp");
    EmpHome empHome = (EmpHome)o;
    return empHome.findByDeptno(getDeptno());
  }
  catch (NamingException n)
  {
    System.err.println("Error loading Employees(Naming): " + n.getMessage());
    return null;
  }
  catch (FinderException f)
  {
    System.err.println("Error loading Employees(Finder): " + f.getMessage());
    return null;
  }

As you can see, the local bean has to lookup the EJB slightly differently, even though they are running in the same container. Also, there is no RemoteException thrown by the find or the create methods, so the exception does not have to be caught.

There is one more difference, and that is in the  ejb-jar.xml deployment descriptor. For an EJB to look up a local EJB, it must point to the correct location using an <ejb-local-ref> tag. If this is not used, the container will not be able to find the bean. For each EJB that needs to use the local EJB, the XML below must be in the deployment descriptor.

  <entity>
    <ejb-name>Dept</ejb-name>
    .
    .
    .
    <ejb-local-ref>
      <ejb-ref-name>LocalEmp</ejb-ref-name>
      <ejb-ref-type>Entity</ejb-ref-type>
      <local-home>ejb.cmplocal.EmpHome</local-home>
      <local>ejb.cmplocal.Emp</local>
      <ejb-link>Emp</ejb-link>
    </ejb-local-ref>
  </entity>
This example will allow the EJB Dept to call the local EJB Emp using the name LocalEmp. This is required because EJBs can have both local and remote interfaces, and to call the EJB Emp via it's remote interface the EJB Dept would look up the name Emp rather than the local reference LocalHome.

An Example

The example zip file contains three EJBs, a servlet and a JSP. There is a stateless session bean (SLSB) ejb.cmplocal.FrontSessionBean calling a local EJB ejb.cmplocal.Dept, which in turn calls a local EJB ejb.cmplocal.Emp. The Entity beans are examples of the Abstract implementation and use the SCOTT/TIGER schema's EMP and DEPT tables. You may notice this is also an example of the Session Facade design pattern, as clients call the session bean, and are hence decoupled from the structure of the database. DeptQuery.jsp demonstrates direct use of local interface by a web client.

 

Configuring your environment

  1. It is assumed that you have the demo user SCOTT created in your Oracle database and the demo tables are created in the SCOTT schema. If you do not have the demo tables install or want to install the demo tables in another schema then execute the demobld.sql located in %ORACLE_HOME%/sqlplus/demo directory of your Oracle database.

  2. Create a data-source in your %J2EE_HOME%/config/data-sources.xml file to point to the SCOTT/TIGER schema or any other schema where the demo tables are installed. You can find the data-sources.xml file used to build the example in the etc directory.

  3. This application uses the default data-source configured for OC4J. If you want to use a data-source other than your default data-source then modify the orion-ejb-jar.xml file to point the data-source you have created by adding the item in red in the tag shown below.
  4.   <entity-deployment name="Emp" data-source="jdbc/OracleDS" table="EMP">
  5. Make sure that you have turned off autocreate-tables as the EMP and DEPT tables already exist. This is done using the orion-application.xml. Make sure the the <orion-application... tag have an attribute autocreate-tables="false".

  6. Examine the code in the following methods, to see how the local EJBs are called.:

    1. DeptQuery.jsp. Notice how local home of Dept EJB is looked up and local interface is used
    2. FrontSessionBeanBean.getDepartmentInformation(). Notice that the lookup to the DeptHome is us
    3. ing the full java:/comp/env/LocalDept syntax.
    4. DeptBean.getEmployees(). As above, notice the syntax of the call to the LocalEmp bean.

     

  7. Examine ejb-jar.xml to make sure that the FrontSessionBean declaration has the <ejb-local-ref> tag pointing to the LocalDept reference to the Dept bean.

  8. Also in ejb-jar.xml make sure that the DeptBean declaration has a <ejb-local-ref> tag pointing the LocalEmp location to the Emp bean.

  9. In ejb-jar.xml make sure that the Emp and Dept beans are declared with a <local>... and a <local-home>... tags.

  10. Examine web.xml to make sure that it has the <ejb-local-ref> tag pointing to the LocalDept reference to the Dept bean.

Compiling and deploying the application

We have provided a build script for building the application using Ant. Alternatively you can use the pre-bulit enterprise archive file  cmplocal.ear located in the lib directory.

Using Ant and admin.jar

  1. Ensure Ant 1.4.x or above is installed on your machine and configured correctly.

  2. Set JAVA_HOME and OC4J_HOME environment variables.  Note: On some operating systems Ant does not currently support the use of environment variables,  if this is the case for your operating system,  please modify the common.xml file located in the root example directory.

  3. From the example application root directory [the directory where the build.xml file is located] execute the following command:
  4. ant

  5. Your should now have a newly created cmplocal.ear file in your < example_home >/lib directory.

  6. Deploy the J2EE application cmplocal.ear to your OC4J R2 instance by executing the following command from the <example_home > directory.
  7. and deploy-usingadmin.jar

You should be now ready to run this demo application.

Running the application

  1. Test the application by accessing the web app at the URL http://localhost:8888/cmplocal

  2. After the welcome page is displayed you can click on [DeptQuery.jsp] link and you will get a web page displaying Dept Information that includes all Departments with DeptNo, DeptName and Location

  3. You can click on [TestServlet ] link and to invoke TestServlet. TestServlet calls a Stateless Session Bean called FrontSessionBean that uses the local Interface of the Dept EJB. You will get a web page displaying Dept Information that includes Deptno, DeptName and No. of Employees.

Summary

In this document you should have: