Have you noticed the number of different types of JAR files that you have to deal with lately in J2EE?! JAR files do not just hold EJBs anymore. Rather, JAR files are being used to store utility classes, web applications, enterprise applications, and Java Connector Architecture (JCA) resource adapters. Additionally, in some scenarios, some JAR files are composed of other JAR files.
Now that most major application servers are supporting dynamic class (un)loading with custom classloaders, what are the issues J2EE developers face when working with all of these packaging technologies? This article discusses some of the nuances associated with J2EE packaging and provides some hints to make you more productive.
Currently, the J2EE 1.3 specification defines an enterprise application packaging unit to be a JAR file with an
.ear extension. EAR files can contain one or more:
Since most web-based J2EE applications are composed of web and EJB applications, the EAR file meets the basic requirements for packaging an application. However, it is lacking in capability for packaging complicated J2EE applications. For example, the following components are often used in a J2EE application, but cannot be declared in an EAR file:
MessageConsumerthat runs as part of a
Currently, all of these components of an application have to be manually configured and deployed through a vendor's administration interface. As the usage of the items listed above increases over time, it will become more important for EAR files to natively support packaging of these components to achieve true J2EE application portability.
Give your questions to Tyler Jewell.
Also in EJB 2:
The most frequent question raised about J2EE packaging is in regards to utility and support classes. When packaging a web application or an EJB application, where should you place these libraries?! If you place these classes into the standard
CLASSPATH of your application server, they will likely lose any unloading ability that Web/EJB applications have that are driven by special classloaders used to load them at deployment. If your Web/EJB applications need to change the version of the libraries that they use, then the dependent library will need to be re-deployed when the Web/EJB application is re-deployed. In this scenario, storing utility classes on the standard
CLASSPATH is not a feasible option, since the entire application server would have to be restarted for each deployment of a Web/EJB application. (Yuck!)
Given the standard definition of J2EE, where are you supposed to place libraries so that they can be re-deployed with an application at runtime? I've seen some creative, yet undesirable, solutions:
Utility classes and JAR files can be placed in the
WEB-INF\lib directory of a Web application. Generally, the
WEB-INF\lib directory should primarily be used for the storage of servlet classes, but servlets/JSPs will look for classes in this directory when loading new ones. If the utility library that you are using is only needed by your servlets/JSPs, then this solution will meet all of your needs. However, if the same libraries are also needed by your EJBs, JMS consumers, or startup/shutdown classes, then this option will not work since the
WEB-INF\lib directory is not visible to these items.
A complete copy of all of the utility libraries is placed in each EJB JAR file in addition to the
WEB-INF\lib directory. When an EJB is deployed, an EJB classloader will only look within its own JAR file for any utility classes that are referenced. It will not look within the JAR files of other EJB applications that have been deployed or in the WEB-INF\lib directory. If all of your EJB applications require the use of the same library, then placing a copy of each of that library's classes in each JAR file will meet your needs. The utility classes will be re-deployable along with the EJB.
The second solution is admittedly gross:
So what is the right solution to this dilemma? One of the possible solutions is to eliminate the need for multiple JARs in your J2EE application by converging all of your EJBs and their utility classes into a single, unified package. The EJB 2.0 public final draft 2 (PFD2) specification is driving some projects to do this. This new version of the specification mandates that entity EJBs participating in a relationship do so using local interfaces and requires both of the EJBs in the relationship to be packaged into the same JAR file. PFD1 allowed EJBs in different JAR files to participate in relationships, further promoting greater modularity of the system, but ultimately limited the persistence optimizations that containers could do for CMP entity beans in a relationship. Now that PFD2 eliminates this capability, many vendors are providing tools that perform EJB JAR convergence. These tools will take as input two valid EJB JAR files and merge their contents and deployment descriptors into a single, unified package. You could potentially use one of these convergence tools to re-package your existing JAR applications.
Keep in mind that even if you converge all of your EJBs into a single JAR application, you will have eliminated copies of your utility library among the EJBs, but a copy will still exist in your
WEB-INF\lib library. Additionally, the need for modularity of EJB applications still exists, since many companies desire to re-deploy EJBs on an individual basis. Since every EJB in a JAR will be re-deployed when that JAR file is re-deployed, an unnecessary amount of deployment processing could occur if your only desire is to re-deploy a single EJB.
With the release of JDK 1.3, Sun Microsystems redefined the "extension mechanism," which is the functionality necessary to support optional packages. The extension mechanism is designed to support two things:
Additionally, the J2EE 1.3 specification's section 8.1.2 mandates that compliant application servers must support the extension mechanism as defined for JAR files. This requires that any deployment tool that references a JAR file be capable of loading any optional libraries defined through the extension mechanism. This also implies that if an application server or deployment tool supports runtime undeployment and re-deployment of EJB applications that use libraries via the extension mechanism, then that tool or application server must also support undeployment and re-deployment of any dependent libraries!
Support for the extension mechanism does not exist for EAR, WAR, or RAR
applications as defined in the J2EE specification, since these applications are not directly loaded by a
ClassLoader instance. Web applications still have to have libraries packaged in the
WEB-INF\lib directory and resource-adapter applications can have libraries bundled directly in the RAR file. Enterprise applications will need to package any libraries within the Web, EJB, or resource-adapter application that requires them. So how does the extension mechanism work with EJB applications? A JAR file can reference a dependent JAR file by adding a
Class-Path manifest attribute. The
Class-Path manifest attribute lists the relative URLs to search for utility libraries. Multiple URLs can be specified in a single
Class-Path entry and a single JAR file can contain multiple
Class-Path entries. For example, a JAR file might have:
Class-Path: log4j.jar xmlx.jar foo/bar/util.jar
NOTE: If you use the extension mechanism in a J2SE application, the
Class-Path manifest entry can reference directories, too. But for J2EE applications that are wholly contained within JAR files, the
Class-Path manifest entry can only reference other JAR files.
The extension mechanism is a nice capability, especially since it is designed to handle circular redundancies by creating a unified class path containing all dependencies in first parsed-based ordering. For example, if the first EJB application parsed is
EJB1.jar and it references:
Class-Path: jaxp.jar EJB2.jar xmlx.jar
A classloader will then parse EJB2.jar that references:
Class-Path: jaxp.jar EJB1.jar
The resulting "application" class path that a classloader would ultimately use would be:
Class-Path: jaxp.jar EJB2.jar xmlx.jar EJB1.jar
The manifest class path will definitely spur better modularity of J2EE packages in the future. Using this model, developers can employ a simple scheme for determining which EJBs should be packaged into a single JAR file and which should be packaged in separate JAR files:
The only limitation that developers are now faced with is locating an application server that fully supports this packaging capability. Developers will need to look for application servers that run in a 1.3 JDK and fully support section 8.1.2 of J2EE 1.3. Without this support, developers will need to fall back to one of the other, less-desirable solutions posted in this article. Happy packaging!
Tyler Jewell , Director, Technical Evangelism, BEA Systems Tyler oversees BEA's technology evangelism efforts that are focused on driving early adoption of strategic BEA technologies into the ISV and developer community.
Read more EJB 2 columns.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.