The slogan "Write once, run anywhere" is Sun's way of characterizing Java's platform portability. However, to most Java developers, the slogan more closely represents a noble, and somewhat lofty, objective, rather than real-world Java application deployment. For example, getting your Java applet code to run the same in both Netscape and Internet Explorer can be a trying exercise. Similarly, coaxing Java applications to run the same way on different Java-compatible platforms sometimes requires diligence, patience, and thorough testing.
Don't get us wrong, though. Java is a great technology, especially when used for server-side solutions. And in our opinion, there is no better environment than the Java 2 Platform, Enterprise Edition (J2EE) to develop Web services. However, when working with Enterprise JavaBeans (EJBs), deploying the same EJB code on different platforms can present similar sets of challenges. Although writing universally deployable EJB code is entirely possible, the code and application server must comply with the same EJB specification version. However, an EJB deployer must often go through a different process to properly install and deploy an EJB from one application server to the next.
From a beginner's perspective, this article addresses some EJB packaging nuances associated with deploying the same EJB code from several different application servers, namely BEA's WebLogic, IBM's WebSphere, and the open source community's JBoss application servers.
The EJB deployment process
The EJB deployment process tends to vary between application servers for several reasons. First, the EJB specification provides minimal guidance in describing how you deploy EJBs. Therefore, vendors adhere to the J2EE/EJB specification to varying degrees; they use their own discretion in defining the deployment process for their specific platforms.
Second, since deployment is an area where application server vendors can add value and uniqueness to their product, they are not motivated to standardize the process. In addition, this lack of standardization presents opportunities for application server and Java IDE vendors to integrate their toolset offerings to facilitate EJB development and deployment -- a process only facilitated if your preferred IDE supports your targeted application server. Nevertheless, the process for deploying a given EJB must be taken on a case-by-case basis, and is usually unique to each application server.
To illustrate this, we experimented with two EJB implementations, a Lightweight Directory Access Protocol (LDAP) stateless session bean and a simple container-managed persistence (CMP) entity bean. In this article, we identify some of the major differences associated with deploying the same EJB code in WebLogic, WebSphere, and JBoss application servers. One notable caveat: we did as much as possible by hand (we wrote our code and deployment descriptors, and created the jar files using vi/Emacs and the JDK's jar utility), all the while recognizing that EJB deployment may go smoother if we use enterprise development tools closely aligned with a specific application server vendor (e.g. VisualAge for Java used in conjunction with WebSphere).
For your convenience, we have created a zip file containing the
ProfileTest examples discussed in this article, which you can download in Resources.
HelloWorldLdap: LDAP stateless session bean example
Our first example is a stateless session bean that retrieves information from an LDAP directory. The user, in this case the client, can specify an alternative LDAP server, email address, and base distinguished name (DN) on the command line, and the EJB will retrieve all attributes for that DN from the specified directory.
Classpath issues can hinder EJB and client compilation. To illustrate that, we chose to add the Netscape LDAP library to our first example. Basically, you need to compile your EJB code using the
j2ee.jar library that comes with the J2EE JDK, or its equivalent (for JBoss, use
jboss.jar; for WebLogic, use
weblogic.jar) in your classpath. When compiling a client, however, you also need to have the vendor's client libraries in your classpath, since the client uses an initial context specific to each vendor, as well as your compiled EJB code. Moreover, WebSphere clients require the deployed EJB jar file on the classpath as well.
After successfully compiling your EJB, you can begin preparing your EJB for deployment. You must have at least one deployment descriptor in your
META-INF directory to deploy your bean. Our one deployment descriptor,
ejb-jar.xml, is located in the example's
META-INF directory, and jarred up with our EJB class files before deployment. Our first example,
HelloWorldLdap.jar, has two directories:
META-INF, both of which are at the same directory level. With the hope of universally deploying our bean, we made an EJB jar package containing the following:
HelloWorldLdap/ EjbLdapbean.class EjbLdap.class EjbLdapHome.class EjbLdapClient.class META-INF/ ejb-jar.xml
We packaged our EJB, using a Unix shell, with the following command:
> jar cvf HelloWorldLdap.jar META-INF/ HelloWorldLdap/*.class
We then attempted to deploy
HelloWorldLdap.jar on the three aforementioned application servers. The following sections explain what we discovered.
BEA WebLogic 6.0 (Service Pack 2)
WebLogic has an EJB preparation utility called
java weblogic.ejbc). It takes two parameters as input: the name of the jar file that contains the classes and deployment descriptors (e.g.,
HelloWorldLdap.jar), and the name you want to assign to the
ejbc compiled jar file (i.e.,
ejbc tool is great when your jar file compiles without errors, but can be quite nerve racking when your EJB is not properly constructed. Nevertheless,
ejbc is a good verification tool that helps identify errors prior to EJB deployment. If you compile your jar file with
ejbc, you can feel confident that your EJB will deploy successfully on WebLogic.
We also experimented with deploying the same jar file without using
ejbc. With simple EJBs, you might be successful, but hot deploying (updating an EJB without having to stop and restart the application server, or without having to first remove the old bean instance) your EJB will not work without using
ejbc. Moreover, you will not get
ejbc's verification that you can deploy successfully.
With WebLogic, you can either deploy your EJB by simply copying the jar file into the
WL_HOME/config/your_domain/applications directory, or deploy it through the Web-based management console. WebLogic is good about alerting you of deployment problems in the server log. The easiest way to verify deployment success is by looking at the Java Naming and Directory Interface (JNDI) tree using the management console. With WebLogic, you specify the JNDI name in another deployment descriptor file called
weblogic-ejb-jar.xml. In fact, this file must exist in your
META-INF directory in order for the example EJB to successfully deploy on WebLogic.
In summary, while we didn't need to modify our original EJB code, we did need to add the
weblogic-ejb-jar.xml deployment descriptor to our
META-INF directory. Second, we found obvious advantages to using the
ejbc utility to prepare our EJB for deployment, and for early problem identification within our bean. We were pleasantly surprised to find our Netscape LDAP libraries already bundled inside the
weblogic.jar library, making our classpath more manageable. Finally, hot deploying WebLogic EJBs is a snap! We just copied our modified jar file into our applications directory, and our changes to the bean immediately took effect, for better or for worse.
IBM WebSphere 3.5
When deploying our EJB on WebSphere, we learned that version 3.5 is not compliant with the EJB 2.0 specification (Version 4.0 is reported to be EJB 2.0-compliant). The WebSphere deployment descriptor is a serialized object, as opposed to an XML file. To facilitate creating serialized deployment descriptors, you must use IBM's Java graphical user interface (GUI) tool, called jetace, to convert your EJB jar file to that serialized format. Apparently, if your EJB is at least EJB 1.1-compliant, the jetace utility will parse the
ejb-jar.xml deployment descriptor found inside your bean to obtain deployment specifics; otherwise, the jetace tool pulls the necessary deployment information directly out of your class files. You cannot deploy an EJB on WebSphere 3.5 without using the jetace deployment utility.
Using the jetace conversion utility, you load your jar file from the File menu. Incidentally, jetace refuses to load EJBs that have a deployment descriptor with a
DOCTYPE header. After loading your jar file, you essentially create a new serialized file, set the appropriate deployment parameters using a series of dialogs, and save it. Only then can you attempt to install your EJB using the WebSphere management console. Another interesting aspect of deploying EJBs on WebSphere is that you must stop and remove your EJB from the management console before attempting to redeploy it. If you redeploy your bean without stopping and removing a previous installation of it, you may inadvertently corrupt the bean, causing it to return odd results at times. Finally, WebSphere does not support hot deployment, since you must stop your EJB and remove it from the management console before redeploying it.
In summary, for our initial EJB package, we only needed to modify our deployment descriptor (
ejb-jar.xml) so that it did not include a
DOCTYPE tag. We also needed to get acquainted with the jetace utility, and this particular deployment process in general.
JBoss is very easy to install and run, and it's free -- distributed under the terms of the Lesser GNU Public License (LGPL). It is almost as easy to deploy EJBs on JBoss as it is to install and run the application server itself. Nevertheless, we still encountered subtle differences when deploying our bean on JBoss.
First, we encountered a problem with the way we had written our original
ejb-jar.xml deployment descriptor. JBoss wants the opening and closing tags of certain tag elements on the same line, as opposed to breaking them up over three lines. For example, the following
ejb-jar.xml deployment descriptor caused a deployment error on JBoss, even though it passed through the WebLogic and WebSphere XML parsers without a hitch:
Initial ejb-jar.xml file
<?xml version="1.0"?> <ejb-jar> <enterprise-beans> <session> <ejb-name> EjbLdap </ejb-name> <home> HelloWorldLdap.EjbLdapHome </home> <remote> HelloWorldLdap </remote> <ejb-class> HelloWorldLdap.EjbLdapbean </ejb-class> <session-type> Stateless </session-type> <transaction-type> Bean </transaction-type> </session> </enterprise-beans> </ejb-jar>
We corrected our formatting errors and ended up with the following
ejb-jar.xml deployment descriptor:
<?xml version="1.0"?> <ejb-jar> <enterprise-beans> <session> <ejb-name> EjbLdap</ejb-name> <home> HelloWorldLdap.EjbLdapHome</home> <remote> HelloWorldLdap</remote> <ejb-class> HelloWorldLdap.EjbLdapbean</ejb-class> <session-type> Stateless</session-type> <transaction-type>Bean</transaction-type> </session> </enterprise-beans> </ejb-jar>
Second, we had to add one additional deployment descriptor, called
Jboss.xml descriptor is analogous to WebLogic's
weblogic-ejb-jar.xml deployment descriptor. It provides the means for binding your EJB name to a name on the JNDI tree.
Deploying a JBoss EJB is as easy as copying your jar file into the deploy directory, located immediately below the JBoss installation root directory. JBoss does support EJB hot deployment. Information about your bean's deployment is conveniently printed out on the command line (on Unix, this is the same shell window in which you started JBoss). One minor annoyance with JBoss, however, is that you can't view the JNDI tree to verify your bean's successful registration, and you can't see your bean's registered name in the JNDI tree. If you fail to specify your bean's JNDI name in the
jboss.xml deployment descriptor, JBoss, by default, will register it using the value you provided in the
<ejb-name> tag, specified in
ejb-jar.xml. With the addition of
jboss.xml, you can specify your bean's registered name on the JBoss JNDI tree by using the
In summary, JBoss is a lightweight application server requiring little deployment overhead to register your EJB. You simply copy your jar file into the deploy directory and watch your console's output for the results. JBoss supports our notion of hot-deployable beans. If we'd taken more care to construct a properly formatted
ejb-jar.xml file, our original EJB could have been deployed on JBoss without modification. However, JBoss does employ the use of additional deployment descriptors as well, like
jaws.xml, making the deployment of more complicated beans more interesting.
Summary of LDAP EJB example
Even in light of our simple LDAP EJB example, it quickly becomes apparent that you must discover your EJB deployment process on a case-by-case basis. Our second example further demonstrates some differences associated with deploying the same EJB code in different application servers. But first, Table 1 summarizes the deployment issues we encountered with this example:
|Hot deployment support||Vendor-specific deployment tools||Additional vendor-specific deployment descriptors||EJB 2.0 compliance|
|BEA WebLogic 6.0 SP2||Yes||ejbc||weblogic-ejbc-jar.xml||Yes|
|IBM WebSphere 3.5||No||jetace||No||No|
ProfileTest: CMP entity bean example
Our next example is a simple entity bean that lets a client add and retrieve data from an Oracle8i data store. This example was meant to be as EJB 2.0-compliant as possible. Like the LDAP session bean described earlier, we attempted to deploy our entity bean on WebLogic, WebSphere, and JBoss application servers.
Before deploying this type of EJB, however, you must first create an Oracle data source and a JDBC connection pool in your application server for the EJB to use. Each product has a different method for creating data sources and connection pools, so you may need to consult the documentation of your specific product before attempting to deploy this example. (You can retrieve the example in Resources.)
BEA WebLogic 6.0 (Service Pack 2)
WebLogic, in addition to the
weblogic-ejb-jar.xml deployment descriptor described previously, requires a deployment descriptor that helps WebLogic map the fields of your bean to the columns in your Oracle table. This deployment descriptor is called
weblogic-cmp-rdbms-jar.xml and must be included in
META-INF, along with
weblogic-ejb-jar.xml. You can configure some application servers to automatically create your database table based on the field mappings found in your deployment descriptors. WebLogic, unfortunately, does not do this for you. You must either create the database table by hand, or write your own utility. The following is a simple script to create the table in Oracle that our entity EJB example requires:
Create table ProfileTest_ProfileBean ( ID NUMBER(10) NOT NULL, PROFILEID VARCHAR2(255) NOT NULL, FNAME VARCHAR2(255), LNAME VARCHAR2(255) );
Our CMP entity bean deployed without incident, but WebLogic did require us to add an additional deployment descriptor called
IBM WebSphere 3.5
As noted earlier, WebSphere 3.5 is not EJB 2.0-compliant. As a result, we had to modifify our original EJB code (see the example source code). After making code changes, which essentially made our code EJB 1.1-compliant, we then recompiled and jarred our EJB. We then used the jetace utility to create a jar file suitable for deployment on WebSphere, and used the WebSphere management console to deploy the bean. WebSphere can automatically create the Oracle database table for you based on the information found in your
ejb-jar.xml deployment descriptor. For example, the following lines in the
ejb-jar.xml file describe the fields in your EJB that need to be container-managed:
... <cmp-field><field-name>id</field-name></cmp-field> <cmp-field><field-name>fname</field-name></cmp-field> <cmp-field><field-name>lname</field-name></cmp-field> <cmp-field><field-name>profile</field-name></cmp-field> ...
Figure 3 shows the WebSphere management console view where you specify whether or not you want your table automatically created when deploying your CMP entity bean.
When using Oracle8i with WebSphere, however, you must first perform some preparation steps within Oracle before attempting to use it as a data source, such as changing the number of allowable open cursors, and creating
EJSADMIN and/or EJB Oracle accounts. When WebSphere creates the table in Oracle, it uses a name based on your EJB's name. In our case, WebSphere created the default table name
Unfortunately, we kept getting a
java.sql.SQLException: ORA-01002: fetch out of sequence error each time we tried to use our client to access the
ProfileTest bean. We could not resolve this problem with IBM's customer support, as custom EJB support is not provided for trial copies of WebSphere. We did, however, successfully call the
create() method on our bean to add records to the database table. As an aside, when using the default data source, which uses DB2, instead of our Oracle data source, our entity bean worked perfectly.
In summary, WebSphere lets you automatically create a database table for your CMP entity bean. However, before using Oracle8i as a WebSphere data source, you must do some initial preparation in the database. Fortunately, no additional deployment descriptor files are required; all you need is
ejb-jar.xml. You must use the jetace deployment utility to create a jar suitable for WebSphere deployment.
Unlike WebSphere, JBoss does not require any up-front modifications to the database server. To paraphrase the JBoss documentation, JBoss uses Jaws, an object-relational data mapping utility, to manage CMP entity beans. By creating a deployment descriptor called
jaws.xml, and including it in your
META-INF directory, you can use this file to tell Jaws to create and remove tables in your database. Further, you can specify the mappings from your bean to column names in your database table. The
jaws.xml descriptor is analogous to WebLogic's
weblogic-cmp-rdbms-jar.xml deployment descriptor; however,
jaws.xml is optional. If you do not explicitly use
jaws.xml to specify the name and schema that you want created, Jaws will create a default table, which will be your package name, followed by an underscore and your bean's name. In our case, Jaws gave our table the default name
jaws.xml is an optional deployment descriptor for deploying CMP entity beans on JBoss, the
jboss.xml file is required. As mentioned in our previous example,
jboss.xml is roughly analogous to WebLogic's
weblogic-ejb-jar.xml deployment descriptor.
While largely EJB 2.0-compliant, JBoss is not fully compliant with the 2.0 specification when it comes to CMP entity beans. As a result, our original 2.0-compliant code would not work inside JBoss either. However, the same code we deployed on WebSphere deployed on JBoss without error (provided the inclusion of
(Note: You can make JBoss compliant with the second draft of the EJB 2.0 spec by using a plug-in offered by a company called MVCSoft Inc. It sells its persistence manager for 8.60.)
In summary, JBoss-bound CMP entity beans require the addition of a JBoss-specific deployment descriptor called
jboss.xml. Optionally, you can include
jaws.xml, which Jaws uses to map bean fields to database table columns and manage those tables, in
META-INF. JBoss 2.2.1 does not yet support CMP entity relationships per the second draft of the EJB 2.0 spec. You can overcome this shortcoming with MVCSoft Inc.'s plug-in. Finally, JBoss, like WebSphere, provides Jaws to automatically create a database table for your CMP entity bean, as indicated by using the
<create-table> tag in your
jaws.xml deployment descriptor.
Table 2 summarizes the deployment issues we encountered when deploying CMP entity beans on the related application servers:
|Support for automatic table creation||CMP deployment descriptor||EJB 2.0 compliance|
|BEA WebLogic 6.0 SP2||No||weblogic-cmp-rdbms-jar.xml||Yes|
|IBM WebSphere 3.5||Yes||No||No|
It's no wonder that the EJB specification calls for the role of an EJB deployer. The job of deploying EJBs can easily be a full-time position, especially if the deployer must target application servers from several different vendors at a time. Unfortunately, the boundaries between those who develop these types of applications, the application deployers, and those who actually administer the application servers themselves is somewhat blurry. As such, each group will most likely need some knowledge of EJB deployment and the issues associated with the process.
When deploying EJBs, the person deploying must learn about the deployment descriptors that accompany the application for a specific app server; how the application gets deployed (i.e., from the command line or management console) and into what directories; what proprietary tools you use to prepare and/or deploy the application; and so forth. The deployment process can be challenging, and will differ from one application server to the next. While not really an art, designing a blueprint for universal EJB deployment can be tricky, time-consuming, and resource-intensive. Hopefully, the lessons learned here will prevent you from reinventing the wheel, so you can devote more time to developing.
Learn more about this topic
- Examples presented in this article
- EJB 2.0 specification
- BEA's WebLogic
- IBM's WebSphere
- MVCSoft Inc.
- LGPL license
- Recent JavaWorld articles for the EJB developer:
- "Optimistic Locking Pattern for EJBs," Yasmin Akbar-Husain and Eoin Lane (July 2001)
- "Java Tip 110Implement the Observer Pattern with EJBs," Roman Stepanenko
- Plus, check out Mark Johnson's new Enterprise Java column in JavaWorld's Topical Index
- Browse JavaWorld's Topical Index for more Enterprise JavaBean articles
- Subscribe to the JavaWorld This Week weekly email newsletter to find out what's new on JavaWorld
- You'll find a wealth of IT-related articles from our sister publications at IDG.net