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