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:

  1. Enterprise JavaBean (EJB) module
  2. Web application module
  3. Application client module
  4. 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.

EAR Structure WAR structure Image description.
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:

  1. WebLogic can deploy the applications more quickly and using fewer resources than deploying applications in archived format. This improves operational agility.
  2. 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:

  1. System classpath loader
  2. WebLogic server classpath loader
  3. Application classpath loader
  4. EJB classpath loader
  5. 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:

  • description
  • weblogic-version
  • jsp-descriptor
  • page-check-seconds = -1
  • precompile = false
  • encoding = the applications encoding
  • package-prefix = jsp_servlet

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:

  • description
  • ejb-name

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://bit.ly/nC7jFS"   

  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://bit.ly/nC7jFS"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4"    xsi:schemaLocation="http://bit.ly/nC7jFS http://bit.ly/7KcNwH">    <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://bit.ly/nC7jFS" 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.