There has probably been a day in your life when you've asked yourself if your web application might use other J2EE concepts besides Java servlets. Your dilemma has most likely been "Although I could read the specifications, I don't have time to set up the containers and enhance the application."
In most cases, that's what keeps people away from leveraging J2EE technologies in their applications. It happens with other architectures, too. However, this doesn't have to last forever, as there are tools to make your life easier. OpenEJB is one--you can run it with no problems after having spent a few minutes reading a quick introduction.
Before we delve into the topic, I'd like to mention that you can find out more details about OpenEJB at the OpenEJB home page.
OpenEJB allows you to use EJBs in your applications with very few configuration files and commands. After reading this article, you will be able to use EJB as you might have been using JDBC with databases like HSQL or Cloudscape. You won't have to spend a lot of your precious time to configure and run an application server. Merely deploy a simple web application from OpenEJB distribution and map the beans deployed in OpenEJB to their respective names in Tomcat's naming system.
OpenEJB can run in two server modes--local (AKA IntraVM) and remote. The main difference between them is the address space (or JVM) in which they run. OpenEJB Local Server runs in the same JVM as the application that uses it. On the other hand, OpenEJB Remote Server runs within its own JVM, probably on a different server than the client application.
The aim of this article is to present an easy yet powerful way of combining Tomcat with OpenEJB so that a web application deployed in Tomcat becomes an OpenEJB client in a fully J2EE-compliant manner. You shall see an EJB example deployed into OpenEJB and accessed by a JSP as part of a web application deployed into Tomcat. I don't want you write the EJB and web application, thus the article provides these components in a downloadable form. We'll concentrate on architecture instead.
I think you'll be amazed at how fast and easy is to enhance your web application with OpenEJB. Home and remote interfaces, stubs, and skeletons will not frighten you anymore!
Needless to say, before we start working with OpenEJB, it needs to be
installed on your system. Download OpenEJB. Be sure to define to define the
OPENEJB_HOME environment variable to point to the directory
where OpenEJB is installed. After that, let's try it out and see how OpenEJB responds.
> cd $OPENEJB_HOME > ./openejb.sh start --------------SUPPORT INFO------------- HP-UX B.11.00 A Using JAVA_HOME: /opt/java1.4 Using OPENEJB_HOME: /disk/home/jacekl/artykul/openejb-0.9.1 . OpenEJB Remote Server 0.9.1 build: 20030118-2102 http://openejb.sf.net ----------------STARTUP---------------- [init] OpenEJB Container System [init] OpenEJB Remote Server ** Starting Services ** NAME IP PORT ejb server 127.0.0.1 4201 admin console 127.0.0.1 4200 -----------------INFO------------------ To log into the admin console, telnet to: telnet 127.0.0.1 4200 --------------------------------------- Ready!
This means everything is indeed "Ready" to go. Press Ctrl-C to stop the session.
The code outlined here will not differ in any way from what you might have
seen at the OpenEJB pages.
It's a simple stateless session bean with a business method--
sayHello(). The JSP will call this method. Download the bean's
Deploying the bean is easy. Invoke the following command under Cygin or any other Unix-like system:
> cd $OPENEJB_HOME > ./openejb deploy -a -f -c <the jar location>
The options given on the command line above are to automate deployment as
much as possible (the
-a option) and forcefully (the
-f option) and to copy (the
-c option) the .jar to the
OPENEJB_HOME/beans directory, overwriting any previously existing
.jar with the same name.
Run the following command to get acquainted with the deploy options:
> ./openejb.sh deploy
When deploying the Hello bean, you shall see the following output:
> ./openejb.sh deploy -a -f -c ~/myHelloEjb.jar --------------SUPPORT INFO------------- HP-UX B.11.00 A Using JAVA_HOME: /opt/java1.4 Using OPENEJB_HOME: /disk/home/jacekl/artykul/openejb-0.9.1 . OpenEJB Deploy Tool 0.9.1 build: 20030118-2102 http://openejb.sf.net This jar contains the following beans: Hello ----------------------------------------------------------- Deploying bean: Hello ----------------------------------------------------------- ==--- Step 1 ---== Auto assigning the ejb-name as the deployment id for this bean. Deployment ID: Hello ==--- Step 2 ---== Auto assigning the container the bean will run in. Container: Default Stateless Container ----------------------------------------------------------- Done collecting deployment information! Creating the openejb-jar.xml file...done Writing openejb-jar.xml to the jar...done Congratulations! Your jar is ready to use with OpenEJB. If the OpenEJB remote server is already running, you will need to restart it in order for OpenEJB to recognize your bean. NOTE: If you move or rename your jar file, you will have to update the path in this jar's deployment entry in your OpenEJB config file.
Tomcat is a servlet container and as such, doesn't host EJBs. That's where OpenEJB comes onto the scene. It's a EJB container. The role of OpenEJB is to create a runtime environment to run EJBs and let others access them in a unified way. Regardless of which application wants to access the beans, they all do it the same way, by accessing the appropriate Java Naming and Directory Interface (JNDI) context and looking up a home object. Think about JNDI as a catalog of names with objects bound to them. JNDI Initial Context is the starting point when working with the catalog--looking up a name or accessing the object bound to it.
This article has been tested under Jakarta Tomcat 4.1.18. Make sure you aren't using the older version.
OpenEJB can run in two modes: Local (AKA IntraVM) Server and Remote Server. The difference is the approach with which they're initialized and then accessed. OpenEJB Local Server requires some OpenEJB-specific .jars to be available in a client's classpath. It will start automatically the first time the JNDI Initial Context is created. The Remote Server must be booted manually. The above command line session demonstrates how this is done for OpenEJB Remote Server. Technically, OpenEJB Local Server is nothing more than OpenEJB Remote Server that doesn't listen on ports, so remote clients cannot connect.
As previously mentioned, Tomcat knows nothing about EJBs other than that it allows them to
be bound in its naming hierarchy, so that JSPs and servlets can access them.
These names are merely names when no EJB container hosts the beans tied to
them. We are about to see the bridge from Tomcat to the OpenEJB runtime
environment. The bridge is an JNDI Object Factory. The factory builds objects
on the fly when they are requested from a naming system. The OpenEJB
TomcatEjbFactory class intercepts bean requests and passes them to OpenEJB.
OpenEJB services the request and responds back appropriately.
If you want to find out more on the
TomcatEjbFactory class, read this
Installation of the factory requires some OpenEJB classes to be available for Tomcat. This is accomplished by deploying a simple web application to Tomcat that loads OpenEJB .jars into Tomcat's class path. A sample application ships with OpenEJB. When Tomcat starts, the web application is deployed and the application's loader servlet executes, loading the .jars.
Deploying the web application boils down to deploying openejb_loader-0.9.0.war from the <OPENEJB_HOME>/dist directory to the <CATALINA_HOME>/webapps directory. Tomcat searches this directory for web applications to deploy when it starts.
You can configure the way the web application works. Edit its deployment
descriptor (/WEB-INF/web.xml) and you'll see the configuration
<init-param>s of the loader servlet:
openejb.home: the path where OpenEJB is installed.
openejb.configuration: the OpenEJB configuration file.
openejb.localcopy: is OpenEJB supposed to copy all variables between beans?
Don't forget to uncomment and update
openejb.home, or OpenEJB
won't be able to find its classes. Once the value has changed, restart
The last step is configuring
TomcatEjbFactory in Tomcat's
default configuration file (server.xml). EJB name bindings appear
<Context> elements of the web application whose
components use the bean. The sample EJB binding is shown below.
Place the following declaration between
examples web application.
<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>
<Ejb> element and its corresponding
<ResourceParams> declares that the name
points to a session bean whose remote interface is
org.acme.Hello, and whose home interface is
<Ejb> element come
parameters. These parameters configure Tomcat to know that whenever the
ejb/hello name is accessed, the factory (of
org.openejb.client.TomcatEjbFactory) should fullfil the request.
<parameter>s configure the
itself, which has to know how to access the OpenEJB server. One of the
<openejb.ejb-link>, which maps
the name from Tomcat to OpenEJB. These are two separate naming systems. Each
has its own naming space, and the names in one must be linked to their
counterparts in the other.
OpenEJB does not need to be started manually in this configuration. As
indicated by the
value, it will be done automatically. Changing the value to
org.openejb.client.RemoteInitialContextFactory says to connect to
OpenEJB that listens to requests at localhost on port 4201. Assuming you have
not changed the OpenEJB configuration, it listens on port 4201.
You can find more configuration information in the OpenEJB TomcatEjbFactory documentation.
Let's test the configuration. Start up Tomcat and look at the output. You should see something like the following:
> ./bin/catalina.sh run Using CATALINA_BASE: /disk/home/jacekl/artykul/jakarta-tomcat-4.1.18 Using CATALINA_HOME: /disk/home/jacekl/artykul/jakarta-tomcat-4.1.18 Using CATALINA_TMPDIR: /disk/home/jacekl/artykul/jakarta-tomcat-4.1.18/temp Using JAVA_HOME: /opt/java1.3 [INFO] Registry - -Loading registry information [INFO] Registry - -Creating new Registry instance [INFO] Registry - -Creating MBeanServer [INFO] Http11Protocol - -Initializing Coyote HTTP/1.1 on port 8080 Starting service Tomcat-Standalone Apache Tomcat/4.1.18 OpenEJB 0.9.1 build: 20030118-2102 http://openejb.sf.net [INFO] Http11Protocol - -Starting Coyote HTTP/1.1 on port 8080 [INFO] ChannelSocket - -JK2: ajp13 listening on 0.0.0.0/0.0.0.0:8009 [INFO] JkMain - -Jk running ID=0 time=4/317 config=/disk/home/jacekl/artykul/jakarta-tomcat-4.1.18/conf/jk2.properties
As you might have noticed, OpenEJB has also started while Tomcat was
initializing the example web application's resources. This is because the
factory had been told to boot OpenEJB Local Server via the
openejb.naming.factory.initial parameter. Therefore, in this
configuration, Tomcat will start up OpenEJB as well.
Having configured Tomcat and the factory, we are now able to look up
ejb/hello in Tomcat's naming space and expect to get hold of the
Hello EJB deployed in OpenEJB.
This code shows how simple it is. Download it here.
Example 1 -- openejb.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> Stateless Session bean - HelloBean - says: <% 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>
Assuming you haven't tweaked Tomcat's configuration too much, save the file in $CATALINA_HOME/webapps/examples. Tomcat's example web applications reside there, and saving the file there shortens the path of deploying a separate web application. (Also, we don't have to learn too much about Tomcat configuration in this article.)
Now it's time to see it working. Start up Tomcat and browse to this URL: http://localhost:8080/examples/openejb.jsp .
Figure 1 -- our application in action
When EJB is mentioned, a few products come to mind. They usually require some time working with configuration files before they're started up and functioning well, especially when combined with Tomcat. Sometimes it's not possible at all. More importantly, they always require installing another platform on your computer that replaces the standalone Tomcat with some platform where Tomcat is a service of some kind. You won't be happy if you've already invested time learning the standalone Tomcat.
As you might have seen, OpenEJB is quite different. Installation boils down to deploying an OpenEJB web application and setting up Tomcat so that some of the JNDI names point to the OpenEJB naming system. Nothing more than that; no changes to already-deployed web applications, no additional configuration files in Tomcat, and frankly, you won't be tied to a specific Tomcat version. So, do we need more benefits? They're coming ...
If anybody says EJB containers require a lot of time to grasp, mention OpenEJB. The development of OpenEJB is ongoing, so it's possible to see more features pertaining to the integration in the future. Make sure to visit the OpenEJB home page often.
Jacek Laskowski is a technical consultant at Hewlett-Packard. In his spare time, he contributes to OpenEJB development.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.