Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Include Page
OPENEJBx30:Tomcat Object Factory
OPENEJBx30:Tomcat Object Factory

Leveraging J2EE JNDI principles

Abstract

Java 2 Enterprise Edition (J2EE) provides several technologies that lets build J2EE-compliant applications that can be run in any J2EE-compliant application server. One of the several technologies is Java Naming and Directory Interface (JNDI). JNDI is a technology that provides a unified access to different naming and directory services. Regardless of the underlaying service, if it supports JNDI a client doesn't have to know what exactly application it's to talk to other than it adheres to JNDI concepts and interfaces.

OpenEJB and Tomcat can complement each other in fullfiling J2EE principles. OpenEJB is an EJB container whereas Tomcat is a servlet container. Although they serve different clients, both products use JNDI extensively. Obviously, either container provides different JNDI "views" of its managed components. The question pertaining to the integration is how to tie the different naming systems so that when a client requests an object from Tomcat naming space, Tomcat will know that it needs to pass the request along to OpenEJB naming space. That's what the object factory is to solve out.

While reading JNDI specification you can come across the interface: javax.naming.spi.ObjectFactory . The javadoc of the interface reads:
This interface represents a factory for creating an object.

The JNDI framework allows for object implementations to be loaded in dynamically via object factories. For example, when looking up a printer bound in the name space, if the print service binds printer names to References, the printer Reference could be used to create a printer object, so that the caller of lookup can directly operate on the printer object after the lookup.
Theorically, it seems to be possible to create a web application that makes use of EJBs, deploy these EJBs in OpenEJB, and the web application in Tomcat, set up an object factory and finally boot it up. The following sections are to outline what exactly the steps are in OpenEJB and Tomcat with description of why they are required at all.

Before we start

Before we start, ensure that OpenEJB and Tomcat are in appropriate releases.

Warning

What follows should be doable on any Tomcat 4.x or 5.x release. The author tested it under Jakarta Tomcat 4.1.18 and 5.0.27 (the most recent public release at that time).

Warning

It's assumed that Tomcat and OpenEJB are already installed and running properly as a separate products.

Referencing EJBs in web application

J2EE 1.3 specification says (page 57):

The Application Component Provider must declare all the EJB references using the ejb-ref elements of the deployment descriptor. This allows the consumer of the application component's jar file (the Application Assembler or Deployer) to discover all the EJB references used by the application component.

It means that each time a web application needs to reference a bean, the bean has to be declared in the web application's deployment descriptor ( /WEB-INF/web.xml file). The element which does so is ejb-ref . Although most containers don't enforce that approach, it's always better to describe dependencies in a standard, J2EE-compliant way, in the deployment descriptor of the corresponding components.

Warning

Tomcat won't refuse to activate the components even if they reference EJBs with no declaration in the deployment descriptors.

Our example's web application declares the referenced bean in the deployment descriptor ( /WEB-INF/web.xml ) as follows:

Code Block

<ejb-ref>
    <description>
        EJB Reference to the bean deployed to OpenEJB
    </description>
    <ejb-ref-name>ejb/hello</ejb-ref-name>
    <ejb-ref-type>Session</ejb-ref-type>
    <home>org.acme.HelloHome</home>
    <remote>org.acme.Hello</remote>
</ejb-ref>

Here goes a JSP that uses the ejb-ref-name to get a reference to the declared bean.

Code Block
titleopenejb.jsp

<%@ page import="org.acme.HelloObject,
                 org.acme.HelloHome,
                 javax.naming.InitialContext,
                 javax.naming.Context"%>

<html>
<head>
	<title>OpenEJB -- EJB for Tomcat</title>
</head>

<body>
<%
    Context initCtx = new InitialContext();

    Object object = initCtx.lookup("java:comp/env/ejb/hello");
    HelloHome helloHome = (HelloHome)
            javax.rmi.PortableRemoteObject.narrow(object, HelloHome.class);
    HelloObject bean = helloHome.create();
%>
<%= bean.sayHello() %>
</body>
</html>

As it's shown in the sample JSP above, there is no direct reference to the EJB container to be used. The application component provider doesn't have to know what container the EJB is to be deployed to. What it does have to ascertain is that the name the JSP uses is actually an ejb reference. Moreover, the reference should be the one to HelloHome home interface or otherwise the application will fail.

Installing OpenEJB's EJB factory in Tomcat

Warning

CATALINA_HOME environment variable points to the directory where Jakarta Tomcat 4.x has been installed.

The J2EE 1.3 specification says (page 56):

The Deployer binds the EJB references to the enterprise bean's homes in the target operational environment.

It means that after an Application Component Provider (in the document, it's you) has created a web application and specified an EJB reference in the deployment descriptor, a deployer (you, too) has to bind the reference in Tomcat. The task boils down to put appropriate entry in Tomcat's configuration file.

Tomcat's default configuration file is server.xml in $CATALINA_HOME/conf directory. According to server.xml's documentation it's possible to create an appropriate definition of a factory and let the factory to handle requests for the objects it is registered to handle. That's what OpenEJB's EJB factory does. It intercepts messages for EJBs, passes it along to OpenEJB and returns requested bean.

Tomcat registers resource factories in GlobalNamingResources or Context elements which demarcate the name space of different web applications.

Warning

It's recommended to place resource definitions within Context elements, which prevents name clashes to occur when the same names are to point to different resources (e.g. EJBs).

The following snippet shows the elements necessary to register the EJB reference, which has been defined in the web application's deployment descriptor. The document doesn't describe the particular elements of server.xml file other than ResourceParams parameters. The reader shall read the Tomcat documentation to get acquainted with the file's structure.

...


<Server>
    ...
    <Context path=...>
        ...
        <Ejb name="ejb/hello"
             type="Session"
             home="org.acme.HelloHome"
             remote="org.acme.Hello"/>
        <ResourceParams name="ejb/hello">
            <parameter>
                <name>factory</name>
                <value>org.openejb.client.TomcatEjbFactory</value>
            </parameter>
            <parameter>
                <name>openejb.naming.factory.initial</name>
                <value>org.openejb.client.LocalInitialContextFactory</value>
            </parameter>
            <parameter>
                <name>openejb.naming.security.principal</name>
                <value>username</value>
            </parameter>
            <parameter>
                <name>openejb.naming.security.credentials</name>
                <value>password</value>
            </parameter>
            <parameter>
                <name>openejb.naming.provider.url</name>
                <value>localhost:4201</value>
            </parameter>
            <parameter>
                <name>openejb.ejb-link</name>
                <value>Hello</value>
            </parameter>
        </ResourceParams>
    </Context>
    ...
</Server>

ResourceParams parameters consitute a bean reference. They inform Tomcat about who will know how to handle requests for the bean.* factory - (mandatory) the class instantiated by Tomcat when a request for a bean has arrived; it must be org.openejb.client.TomcatEjbFactory if the request ought to be handed over to OpenEJB.

  • openejb.naming.factory.initial - (mandatory) OpenEJB JNDI InitialContext implementation; the parameter may be assigned to one of the two values:* org.openejb.client.LocalInitialContextFactory - OpenEJB is started in the same JVM as Tomcat; it boosts performance drastically as the beans are in the same JVM as a client (e.g. a web application); it boots up OpenEJB in the local mode - an Local (aka IntraVM) Server instance
  • org.openejb.client.RemoteInitialContextFactory - OpenEJB is started outside of the current JVM; all calls are forwarded to a OpenEJB Remote Server instance
  • openejb.ejb-link - (mandatory) the bean's name to be looked up in OpenEJB; the name doesn't have to be the same as the reference's name in Tomcat; it's the name the bean may be found in OpenEJB JNDI name space.

The following parameters are only required when openejb.naming.factory.initial is set to org.openejb.client.RemoteInitialContextFactory .* openejb.naming.security.principal - the name of the user who is allowed to access the JNDI context

  • openejb.naming.security.credentials - the password of the user who is set up in openejb.naming.security.principal parameter
  • openejb.naming.provider.url - the server and port OpenEJB handles remote requests

The factory parameter indicates the class which passes a request for a bean to OpenEJB instance. In order for the class to be instantiated by Tomcat, OpenEJB Loader has to be installed. The Loader takes care of loading necessary classes from OpenEJB directory. It finds the directory relying upon OPENEJB_HOME environament variable.

Create a file named setenv.sh (or setenv.bat on MS Windows) in $CATALINA_HOME/bin directory with the following content:

Code Block
title$CATALINA_HOME/bin/setenv.sh

export CATALINA_OPTS="-Dopenejb.home=$OPENEJB_HOME"

Finally, add the OpenEJB Loader to Tomcat.

Code Block

$ cp $OPENEJB_HOME/dist/openejb_loader-0.9.0.war webapps/

That's it. Tomcat is now fully configured to work with OpenEJB. Don't forget to start up OpenEJB instance if the factory's been configured with RemoteInitialContextFactory.

Example application

You can use the OpenEJB Hello World as an example EJB to test things out. You won't need to do anything differently. Deploy the myHelloEjb.jar just as described in http://www.openejb.org/hello-world.html

Register the factory in Tomcat by editing server.xml, i.e. add the above Ejb element declaration between Context's tags of Tomcat's default example web application. Place the JSP - openejb.jsp - in $CATALINA_HOME/webapps/examples directory.

Start up Tomcat and enter http://localhost:8080/examples/openejb.jsp . As a result, you should see "Hello World!!!!!" on the screen.

Tomcat should print out the following on its console (note OpenEJB messages about its startup):

...