Best Practices for Building Production Quality EAR Files
by Hussein Badakhchani
02/13/2008
Abstract
In this article I examine the options available for packaging and
deploying Java EE applications. I will start by reviewing the Java
EE 5 specifications pertaining to application assembly and deployment.
Next I will set out packaging specifications for production EAR files
and review some of the techniques you can use to implement and enforce them.
This article is aimed at those responsible for creating or enforcing
standards and those who regularly troubleshoot application deployments.
The primary audience will therefore be BEA WebLogic administrators; however, anyone
who has an interest in ensuring application deployments run smoothly will
benefit from reading this article.
Introduction
Packaging applications for deployment onto production servers is an
integral part of Java EE projects. As more and more projects are
developed offshore, the requirement for clear and justifiable packaging
specifications becomes even more relevant. Incorrectly packaged
applications can lead to subtle errors that require experts to resolve through
lengthy analysis. Such problems are often intermittent—for example, different deployment mechanisms (and there are several available
for WebLogic Server) can either mask or trigger deployment errors.
These problems are compounded by
a general ignorance of the nature of the problems that can be caused by poor
packaging and lack of clear error messages when they occur. All too often,
the causes of deployment failures are overlooked due to the pressure
to get the application deployed. A good WebLogic administrator will find a workaround
and complete the deployment even if that means simply redeploying the
application. However, if
the root cause of the failure is not identified and resolved, the defect will
resurface in latter test phases, where it can be costly and time consuming
to resolve and can increase the risk of delivering the project on time. In the worst case,
scenario deployment failures are not even considered defects but simply accepted
as part of the behavior of the application.
Java EE Application Assembly and Deployment
Before we begin to look at the details of the Java EE 5 specification relating to deployment, we need to
understand the goals of the specification. Chapter 8 of the
specification, "Application Assembly and Deployment," states the goals
clearly as "This chapter specifies Java Platform, Enterprise Edition
(Java EE) requirements for assembling, packaging, and deploying a Java
EE application. The main goal of these requirements is to provide
scalable and modular application assembly, and portable deployment of
Java EE applications into any Java EE product."
In general terms, the specification is concerned with balancing
the needs of the stakeholders it identifies using platform roles, for
example the deployer, the system administrator, and the tool provider.
This balancing act, or perhaps more unkindly, the compromise, affords
some flexibility to the end user but at a cost. As the details of
packaging are left up to the user to decide, a high degree of variance
can occur in the packaging of different applications, especially if they
have been created by desperate project teams. We need to be
familiar with the specification to ensure we adhere to it
where necessary and justify any restrictions we impose on it.
The Java EE Application
The Java EE application is composed of up to four types of Java EE
modules and an optional application deployment descriptor. The modules
are:
- Enterprise JavaBean (EJB) module
- Web application module
- Application client module
- Resource Adapter module
Like their parent application component, all of these modules
have specific directory structures and
deployment descriptors that are expected by all Java EE containers. There is also a provision to include container-specific deployment
descriptors. As an example, the Web application module can contain
a weblogic.xml deployment descriptor. The figures below depict the
standard structure and deployment descriptors of three most common
application components: EARs, WARs, and EJBs.

|

|

|
|
Figure 1. EAR file structure
|
Figure 2. WAR file structure
|
Figure 3. EJB file structure
|
Packaging Best Practices for Production Environments
When deploying applications onto production environments, security,
performance, and operational agility are overriding concerns.
WebLogic administrators need to be able to deploy applications
quickly and with minimal manual intervention.
These requirements can be satisfied without code changes using a
combination of deployment descriptor and application server
configurations as well as packaging applications properly
and consistently across all projects.
The following packaging best practices
we will review are a culmination of best practices that help to
ensure applications deployed to WebLogic domains will deploy.
Whether or not an application actually works after it is deployed is,
of course, the concern of the developers.
Obviously, not all the
specifications will apply to you or your organization, and you may not agree
with all of them; what is important is to have some packaging specifications
in the first instance and to be able to justify them.
PS001: Deploy applications in exploded format
Deploying applications in exploded format provides the following benefits:
- WebLogic can deploy the applications more quickly and using fewer resources than deploying applications in archived format. This improves operational agility.
- It allows application support teams to make changes to configuration files more easily and quickly than if they were deployed in archived format.
If the deployment time of your application is a factor in service down time, then deploying in exploded format can reduce the risk of an SLA breach as most of deployment time is consumed by the container unzipping each application component. This benefit is magnified if you are deploying lots of separate applications or large application packages onto your servers routinely. If, on the other hand, application deployment does not cause any down time, is an uncommon activity, or you have a policy of signing your JAR files, you may not want to use this practice.
PS002: No duplicate JAR files in EARs
WebLogic follows a delegate class-loading model. Classes are loaded in the following order:
- System classpath loader
- WebLogic server classpath loader
- Application classpath loader
- EJB classpath loader
- Webapp classpath
This means that JAR files placed in APP-INF/lib will be visible to Web applications. No JAR file should exist in both APP-INF/lib and WEB-INF/lib. This increases the size of the deliverable, increases deployment times, and risks creating class-loading problems and deployment failures.
Ideally, all JAR files should be defined in APP-INF/lib only, unless there is an overriding requirement to deploy different versions of a JAR file for different modules in the EAR file.
For more information, refer to WebLogic Server's classloading mechanism.
PS003: JSPs, unprocessed/uncompiled annotations and source files must not be included in the EAR
Configuring WebLogic servers with a compiler on production environments is a security risk, as is including tools.jar on the system or WebLogic classpath. Using precompiled artifacts eliminates the need to configure a compiler and also reduces application initialization time, improving the perceived response time of the application when it is first accessed by users. Ensuring all artifacts are compiled at build time also means compile time errors are identified and fixed at compile time (rather than once the application has been deployed).
For these reasons, all artifacts in the EAR must be fully compiled before they are deployed. JSPs must be compiled using the latest version of BEA's Appc tool that is compatible with the version of WebLogic being used by your project. Annotations must be processed and compiled using the version of apt supplied by the JDK version being used by the project.
Interestingly, one of the objections to this practice came from a developer who insisted that annotations are not compiled. I pointed him to Sun's apt tool Web site, which reads "apt first runs annotation processors that can produce new source code and other files. Next, apt can cause compilation of both original and generated source files, thus easing the development cycle." Funny how pedantic some developers can be. To be clear, the semantics of compilation or processing are a distraction. The point is to ensure only versioned binaries are deployed to live servers.
I have worked on projects where tools.jar was left on the classpath and the WebLogic Server console application itself, if not properly processed, had a dependency on it. WebLogic Server 9 users should be aware of this caveat.
PS004: JAR files that are supplied by the system or WebLogic classpath should not be included in the EAR
Including JAR files that are on the system or WebLogic classpath in applications can cause class-loading issues if the JAR files on these class loaders are upgraded by the infrastructure team. It also increases the size of the deliverables and increases deployment times (see PS001 and PS002). If you ever have to deploy a JAR file onto the system classpath, you should ensure that there is a valid reason for doing it. Managing JAR files on the system classpath is an overhead that is best avoided.
PS005: Ensure all EAR files include a weblogic-application.xml descriptor.
Applications that use WebLogic extensions must include a weblogic-application.xml descriptor. If web-app modules are included in the EAR, then the webapp.encoding.default or webapp.encoding.usevmdefault must be explicitly defined to ensure application portability and to remove any ambiguity of character encoding used by the application. Although not supplying container-specific deployment descriptors is perfectly acceptable in the Java EE specification, on a practical level omitting these descriptors can uncover bugs in the container's deployment code.
When I see applications that don't include container-specific deployment descriptors, it indicates to me that the application is not finished or a lack of attention has been paid to how and where the application is to be deployed.
PS006: Ensure all WAR files include a weblogic.xml descriptor
At a minimum the weblogic.xml deployment descriptor should contain valid, non null arguments for the following elements:
I am always surprised by the resistance to including a weblogic.xml deployment descriptor in a WAR file. In the time it takes to explain all the reasons why it is good practice to include this file to a developer and their manager, they could have copied a file from the WebLogic examples into source control and deployed the application. Ultimately, not including a weblogic.xml deployment descriptor leads to some of the most problematic and costly deployment failures I have seen across every version of WebLogic Server I have worked with.
One case I came across recently was an application that did not ship with a weblogic.xml deployment descriptor. However, as it turned out, for the application to function anywhere outside the developer's own PC, it needed to define the security-role-assignment element correctly. Obviously, this defect is application related, but it serves as a good example of an issue that can disrupt deployment. In many organizations, there is no reason to assume a WebLogic administrator, responsible for application deployment, will know what the required value for this element should be. However, if the deployment descriptor was included in the error messages, it may give the administrator a fighting chance to diagnose the issue.
PS007: Ensure all EJB files include a weblogic-ejb-jar.xml descriptor
At a minimum the weblogic-ejb-jar.xml descriptor should contain valid non-null arguments for the following elements:
Again, for the same reasons as PS005 and PS006, it is good practice to include a container-specific deployment descriptor, even if your application does not leverage any container-specific features.
PS008: Build artifacts must not be included in the EAR file
Build artifacts, such as build.xml or pom.xml files, must be filtered from all deployable packages. This specification is really a good house keeping measure; don't deploy anything more than you need to deploy. Finding build.xml files and pom.xml files in a package indicates a sloppy build process. If your deliverables are being sent to a third party, then there is a real security issue here as well.
PS009: Test artifacts must not be included in the EAR
All test artifacts should be removed from deployable packages, for example the JUnit family of JAR files and the test cases that use them. Again, don't deploy more than you need to deploy. Including these files needlessly increases the size of your application packages and is sloppy.
PS010: Static content must not be included in the EAR
In environments where proxy Web servers are used to serve static content, the static content should be removed from the EAR file. This ensures any misconfiguration of the infrastructure stack or buggy application code, which allows static content to be served by WebLogic, is quickly detected and resolved. This is especially important if your application uses a large amount of static content because of the impact it can have on deployment time (see PS001).
PS011: Configuration files must be consistently named and located
Ideally, application configuration pertaining to an application's environment, which is stored in flat files, should be stored in the applications deployment descriptors. If the application does require specific property files in which to store configuration information, then these files must be consistently names and located. I will elaborate on this in the implementation guidelines later on. On a related matter, I would minimize the use of environment parameters specified on the Java command line to configure applications.
PS012: Out-of-container JAR files must not be included in the EAR
JAR files used in out-of-container implementations of the application must not be used in any EAR that is deployed onto production infrastructure. Out-of-container testing is used by developers who find it difficult to run their code inside a container. An unfortunate consequence of this approach is that the JARs that are used in out-of-container implementations, those that provide interface and implementation classes for Java EE standards—for example, JTA and servlet specification JARs—are included in the application package. This can cause all manner of class-loading issues once the application is deployed—especially if the application attempts to manage its own class loading.
PKS013: Use of Class-Path header in MANIFEST.MF file to load libraries is prohibited
The burden of managing classpath and class loading is overly complicated when using Class-Path headers in Manifest files of JARs. Dependent JAR files should be located in the APP-INF/lib folder of the application or in a designated directory defined in the library-directory element of the EAR file's deployment descriptor.
PS014: EAR names and versioning must conform to the company nomenclature
Ensure application EARs are named consistently and in conformance with your company nomenclature, naming standards, and conventions. This will simplify the automation of application deployment and other processes that work with application EARs.
PS015: Webapp modules in the EAR must be named after their context root and end in the .war extension
By following this practice, application support teams and build tools can quickly determine the context root of the application simply from its name. The application's static content can be easily identified as well.
Implementation Guidelines
With any set of specifications it is helpful to provide a reference implementation.
In this section we will review how to implement a subset of the specifications we have defined. We will discuss PS003, PS005, PS006, PS007, PS010, and PS011.
PS003: Remove uncompiled files
JSPs, uncompiled annotations, or any other source files must not be included in the EAR. In order for WebLogic to delegate requests for JSPs to the compiled class file, the following stanza must be added to the web.xml file of the web app module.
<servlet>
<servlet-name>JSPClassServlet</servlet-name>
<servlet-class>weblogic.servlet.JSPClassServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>JSPClassServlet</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
PS005: Include weblogic-application.xml deployment descriptor.
Here is an example weblogic-application.xml descriptor.
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-application xmlns="http://www.bea.com/ns/weblogic/90"
xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-application.xsd">
<application-param>
<param-name>webapp.encoding.default</param-name>
<param-value>UTF-8</param-value>
</application-param>
</weblogic-application>
PS006: Include web.xml deployment descriptor.
Here is an example web.xml descriptor.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<description>
The Monitor application is used by WhatsIt infrastructure for system validation testing.
</description>
<servlet>
<servlet-name>JSPClassServlet</servlet-name>
<servlet-class>weblogic.servlet.JSPClassServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>JSPClassServlet</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
</web-app>
PS007: Include web.xml deployment descriptor.
Example weblogic-ejb-jar.xml descriptor:
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-ejb-jar xmlns="http://www.bea.com/ns/weblogic/90"
xmlns:j2ee="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-ejb-jar.xsd">
<weblogic-enterprise-bean>
<description>Example EJB</description>
<ejb-name>BeanManagedAccountEJB</ejb-name>
....
<weblogic-ejb-jar>
PS010: Static content must not be included in the EAR
Static content should be delivered in a JAR file with the following structure:
<Webapp Content>
|--css
|--images
|--index.html
The index.html file should redirect the user to the value of <welcome-file list> element of the web app modules web.xml file. For example, if the webapp module uses JSF, the index.html will look like this:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Redirect to JSF controller</title>
<meta http-equiv="REFRESH" content="0;url=http://mydomain.com/webapp/index.faces"/>
</head>
<body>
</body>
</html>
This will ensure that once the JAR file is exploded, every Web application will have its static content located in a consistent and recognizable directory structure.
PS011: Names and locations of configuration files
Application configuration should be maintained in a file named env.properties for all EARs. These files must all be located under APP-INF/lib/classes.
Enforcing Packaging Best Practices
Now that we have a set of packaging best practices and guidelines
for implementing them, you may rightly ask how you can enforce them.
Obviously, you don't want to spend hours pouring over every newly built
application.
A good place to check application packages for
packaging specification compliance is right after the application has
been built, so writing a custom
Ant task or extending Maven's
Verifier plugin
is probably the best solution. Also, remember that invariably there will be
sound reasons to grant concessions, either temporary or indefinite, to allow
an application to violate your specifications. Any violations should be recorded
in the application's release notes along with the ending date of the concession.
Summary
I want to emphasize that the packaging
best practices detailed here are not meant to be prescriptive—
rather, you should use them as guide to implementing your own specifications.
Undoubtedly, there will be a degree of opposition to your measures, so make sure
you can justify them. Ultimately, if you are responsible for the successful
deployment of applications onto your servers, packaging specifications are an
indispensable aid to meeting your objectives.
Resources
Hussein Badakhchani is an independent consultant and middleware analyst
with over 10 years experience in software design, development, management
and support.
Return to Dev2Dev.
Do you agree with Hoos? Have your own suggestions? Let us know:
Showing messages 1 through 11 of 11.
-
great artcile
2008-04-01 01:58:53 t_g_nielsen
[Reply | View]
Hey hoos, great work. I meant to respond earlier but I've been a bit distracted recently. I know that I will be sending all J2EE developers to view this article before they try and hand me some cobbled together EAR. I still like the idea of pushing developers to produce package specs, and its much easier when they have an article like this to refer to.
-
Some best practices really depend on the project
2008-03-20 09:06:01 jcloyd
[Reply | View]
I think this is a fabulous article, so thanks so much for posting this level of detail. As always, applicable best practices really depend on the specific uses, so I wanted to throw out 2 things I saw as more controversial.
- PS001: Deploy applications in exploded format: I often recommend that folks do not do this for a couple of reasons, the most significant of which is you really don't want people to be able to easily modify things on production servers, as it can lead to breaking a disciplined deployment cycle and can easily lead to changes made in production that never make it back into the version control system. Also, deploying as an expanded EAR means you have to handle moving code into the production environment and then expanding it consistently, so you often end up writing scripts to do exactly what is already performed by WebLogic Server. In the extreme case, I've even seen cases involving incorrect file timestamps and versions of JARs left behind throwing things off, which is prevented by moving an entire application as an archive and letting the app server worry about the details.
- PS010: Static content must not be included in the EAR: This is a great recommendation for cases where you're already using a proxy plug-in and a web server, but when you're not, I wanted to clarify that it often times doesn't make sense to add a web server just for this reason. Today, more and more traditionally static content is becoming dynamic (e.g., images pulled from a content management system or user-customizable style-sheets), so in those cases there's very little true static content, so adding a web server really just introduces an additional layer of complexity and overhead that can often be best accomplished with the use of a hardware load-balancer off-loading/accelerating SSL.
--joe
-
Some best practices really depend on the project
2008-03-24 10:52:31 hoos
[Reply | View]
These are both valid points and ultimately depend on existing practices in your organisation. With respect to PS001 I would advocate not jaring your deployments at any stage. APPC can happily compile code given a directory structure, however if you do have to script the exploding of your jars then the script does need to be thoroughly. It is true that it is easier to tamper with a directory structure than a jar but in reality if you do not sign your files or jars you have no way of telling. If your production team are prone to making changes on live servers I would suggest the real issue is one of access control rather jaring or exploding applications.
There are lots of reasons for having a Web server or proxy tier but I think the main reasons have to be security and performance. A proxy tier adds a layer of indirection to your network security and for a lot of organisations this is a standard deployment feature. It also allows the cheaper proxy machine to take some load from the expensive application servers. I agree that if your organisation does not have seperate Web servers you should not implement it one based on PS010.
Thanks for the great feedback.
-
Thanks for putting the article
2008-03-19 05:33:47 zamir.arif
[Reply | View]
For me its quite helpful. I am a novice in weblogic, Can you suggest me some document which may help me to migrate my Spring based web application from tomcat 5.5.x to weblogic 10.3.
-
my 2 cents
2008-02-23 03:18:17 e.legoulven@lectra.com
[Reply | View]
Thanks for this article, putting lights on the 'bea' packaging recommandation.
As I've been able to overcome the packaging compatibility agains WAS6.x/JBOSS4.x/WLS9x, I do not completely agree with the PKS013 recommadation : Use of Class-Path header in MANIFEST.MF file to load libraries is prohibited
since effort spent in specific app server vendor deployment descriptors generation -I'm talking about the 1.4 jee spec-, revealed much more important than war/ejb class-path lib dependency declaration built up, and happens to be at the end one of the rare common packaging item our team has had to customized to match app-server vendor environment specificity.
Rgds
-
my 2 cents
2008-02-23 13:23:31 hoos
[Reply | View]
Thanks for the feedback, I appreciate it. PKS013 was in response to troubleshooting a few issues that took weeks to resolve and required us to peak inside multiple jar files to figure out why we were running into class loading problems.
When the same set of problems appeared in other projects and took longer for less experienced engineers to resolve we thought we had to take steps to mitigate the real cost of using the MANIFEST.MF to declare class paths and hence we thought PKS013 was the best approach.
-
my 2 cents
2008-02-23 13:10:29 hoos
[Reply | View]
Thanks for the feedback, I appreciate it. PKS013 was in response to troubleshooting a few issues that took weeks to resolve and required us to peak inside multiple jar files to figure out why we were running into class loading problems.
When the same set of problems appeared in other projects and took longer for less experienced engineers to resolve we thought we had to take steps to mitigate the real cost of using the MANIFEST.MF to declare class paths and hence we thought PKS013 was the best approach.
-
Very true and thats whats so wrong
2008-02-21 05:31:47 ryanyoder
[Reply | View]
You are right. You really need to build container specific deployment units (wars ears etc). You have to understand the innards of the version of each container you are deploying on and must build customized ant scripts, properties files, war files etc and thoroughly test on each and every environment in order to have a chance of success. Supporting Weblogic 8.1, 9.2, flavors of WebSphere (AIX and Windows), Tomcat 5.0, 5.5, Jboss 3.2, 4.0 etc with its various classloader configurations is a daunting task. Thanks for all the Weblogic 9.2 specific info. If only we had strong named jar files this may not be necessary...
-
Very true and thats whats so wrong
2008-02-22 06:25:46 hoos
[Reply | View]
Thanks for the comments, I have not heard of strong named jar files before but if you think they can avoid a such issues I would like to know how. Can you please elaborate on what a strong named jar file is and their benefits?
-
Very true and thats whats so wrong
2008-04-23 11:51:46 ryanyoder
[Reply | View]
You haven't heard of them because they don't exist :) I'm no expert in classloading but afaik the java classloader and run-time type identification is built on weak references such as package name, class name plus (as of Java 1.2 I believe) classloader.
With DotNet and COM you have the ability to sign your assemblies (dlls) and strong name them. When you reference a dll that is strong named you can only run against that dll. You can also chooose to load certain assemblies with version numbers that are not signed if you don't want to go that far.
When deploying a dotnet application onto someone elses IIS instance you rarely run into a classcast exception because something you hadn't expected is being loaded instead of your class. It just doesn't happen.
Java needs to have a way to sign a jar and to reference a signed version of a jar explicitly or automatically when compiled against a signed jar. That would really make things easier. If I compile against saaj.jar 1.xyz then I shouldn't be handed classes from saaj.jar 1.25 or just because the Weblogic instance has that jar file or even worse because it packages saaj.jar classes inside the 32mb weblogic.jar file.