Packaging

Let's begin by looking at how to package J2EE applications.

Deployment Units

The two most commonly used deployment units inJ2EE applications are Web ARchives (WARs) and EJB JAR files. These are JAR-format files that contain:

  • The implementation classes, binary dependencies, document content (such as JSP pages, static HTML and images) and deployment descriptors of a web application. If we don't use EJB, a WAR can contain all code and binaries required by a J2EE web application.

  • The implementation classes and deployment descriptors of an EJB deployment, which may include multiple EJBs.

Typically, each of these deployment units will include both standard J2EE and proprietary, application server-specific deployment descriptors.

WAR and EJB JAR deployment units comprising an application using the entire J2EE stack can be included in a single J2EE deployment unit, called an Enterprise Archive (EAR). EAR files contain an additional deployment descriptor, application.xml, which identifies theJ2EE modules composing the application. In this book we've considered the WAR and EJB JAR file module types, which are used most often in practice. It is also possible to include Java application clients and J2EE Connector Architecture (JCA) Resource Adapters in an EAR.

Where collocated applications are concerned, EAR deployment is usually the best option, providing convenient deployment and accurately reflecting the semantics of the application. Hence we'll use it for the sample application.

However, EAR deployment may be less appropriate for distributed applications. It's pointless to adopt a distributed architecture if web-tier components on each server always use EJBs on the same server. Thus in a distributed application, the EJB client components (WARs) in an EAR are likely to communicate at runtime with EJBs running on another server, rather than the EJB instances on the same server. One of the key arguments in favor of adopting a distributed architecture is the potential to devote additional hardware to known bottlenecks -for example, EJBs that perform time-consuming processing. In such cases, EAR deployment of all components on all servers may be wasteful and misleading, as the aim is not for all servers to run all application components.

The alternative to EAR deployment for distributed applications is to separate web applications from EJB deployments, as we know that EJBs will be invoked via RMI. However, deployment in separate modules may be more complex. We will need to include the EJB client views (home and component interfaces, but not EJB implementation classes and any helper classes they use) in both EJB and web deployments.

As we noted in Chapter 2, it's possible to run the J2EE Reference Implementation's Verifier tool against an EAR, WAR, or EJB JAR deployment unit, to check compliance to theJ2EE specifications. The sample application's Ant build script includes a target to run the verifier. Such verification should be performed regularly, to ensure that applications are specification-compliant and because it provides an easy pre-deployment check for errors. The verifier tool reports problems such as missing classes or invalid deployment descriptors in a detailed and consistent manner. This may provide clearer information on the cause of a deployment failure than the output of someJ2EE servers.

Expanded Deployment Units

Most servers allow deployment units to be deployed in "expanded" or "exploded" form: that is, as a directory structure, rather than an archive in a fixed directory structure. Expanded deployment is typically most useful in development; we will want to roll out single deployment units into production.

The advantages of expanded deployment in development are that it often enables individual files to be updated without full redeployment. For example, it's unacceptable to have to redeploy an entire application to modify a JSP during development. The sample application's Ant build script includes a target to deploy the application as an EAR containing an EJB JAR file, but an expanded WAR. This makes it possible to modify JSP pages and other web content, without redeploying the application.

Understanding J2EE Class Loading

Perhaps the toughest issue in packagingJ2EE applications relates to class loading in applications consisting of multiple modules, this affects:

  • How we package applications, and especially where we include classes used by both EJB JAR and WAR modules.

  • Portability between application servers. Differences between class loading behavior in different application servers can be a real problem for portability, and can mean that an EAR that works on one server may not work in another, even if it is coded within the J2EE specifications.

Important 

Unless we understand how J2EE server class loading is likely to work and draw the appropriate lessons (we can only say "likely" as it differs between application servers), we risk encountering mysterious ClassNotFound or ClassCastExceptions.

While there are good reasons for class loading to work the way it does, unfortunately the complexity of J2EE class loading can impact application developers and reduce productivity. Thus it is important to understand the issues involved, complex though they are.

Note 

The following discussion concentrates on packaging applications in an EAR (the commonest approach in practice), rather than packaging EJB JAR and WAR modules separately.

Java Class Loading Concepts

Let's first look at how Java 2 class loading works. The following two basic principles will always apply:

  • Each class retains an association with the class loader that loaded it. The getClassLoader() method of Java.lang. class returns the class loader that loaded the class, which cannot be changed after the class is loaded. This is the class loader that will be used if the class attempts to load classes by name.

  • If the same class is loaded by two class loaders, classes loaded by the two class loaders will not be type compatible (although serialization will work).

The documentation of the java.lang. ClassLoader class further defines the following behavior for class loaders:

  • Class loaders are hierarchical. When a class loader is asked to load a class, it first asks its parent class loader to try to load the class. Only if the parent (and parent's ancestors) cannot load the class, will the original classloader attempt to load the class. The top of the class loader hierarchy is the bootstrap loader built into the JVM, which loads java.lang. object().

  • Although a class loader can see classes loaded by its parent(s), it cannot see classes loaded by its children.

As it's possible to implement a custom class loader (and most application servers provide several), it is possible to depart from the hierarchical behavior described in the last two bullets.

Class Loading in J2EE

J2EE servers use multiple class loaders, largely because this allows dynamic application reloading. Clearly we don't want to reload all the application server's own classes on redeploying an application. This would mean that the application server would always need to be restarted. So application servers use different class loaders for application code to those they use for their own standard libraries, for example. Typically one or more new class loaders will be created for each application deployed on a server.

However, multiple class loaders are not usually used for different application-specific classes in the same application unless we use EJB (JSP pages may be given a separate class loader, but this doesn't usually affect application code).

As I've previously mentioned, using EJB considerably complicates the deployment model, compared to that for a pure web application. This is also true of class loading. In a WAR, we can simply include all binary dependencies in the /WEB-INF/lib directory. However, things get more complicated when WARs access EJBs.

To see why, let's consider a common approach to implementing class loading in application servers. In an application deployed as an integrated enterprise application in an EAR, the EJB class loader is often the parent of the WAR class loader. Orion and WebLogic, for example, both use this approach. This is a natural implementation approach, as WARs will typically access EJBs (and therefore need to be able to see at least EJB client classes), while EJBs do not access web components.

Important 

However, it's not the only valid implementation approach, so the following discussion doesn't apply to all application servers.

The resulting class loader hierarchy will look as shown in the following diagram. Actually more class loaders may be involved, but these are the three class loaders most significant to application code.

In this diagram the class loader hierarchy is represented by enclosing boxes. The parent-child relationship is represented by an enclosing box:

click to expand

Assuming standard J2SE hierachical class loading behavior, such a hierarchy will mean that any class can access classes in boxes that enclose its class loader. However, classes associated with the outer boxes cannot load classes in the inner boxes. Thus web application classes can see classes deployed in the application's EJBs and system classes. However, EJB classes cannot see web application classes, and classes installed at server-wide level cannot see any application-specific classes.

Class Loading in Integrated Enterprise Applications

Surely this is all of interest only to implementers ofJ2EE application servers? Unfortunately, application developers can't afford to ignore, or be ignorant of, the implications of J2EE class loading.

Assuming the class loader hierarchy described above, let's consider a plausible scenario. Imagine that an application class or a framework class used in both EJB and web components attempts to load a class within a WAR. Imagine, for example that a BeanFactory implementation used in the EJB container is also used by code within a WAR to load classes by name and manipulate them. Even though this infrastructure class is visible in the WAR, it cannot load WAR classes. Since it was loaded by the EJB class loader it cannot see classes in the WAR, which were loaded by a descendant class loader.

We can't always solve this problem simply by holding class definitions in both WEB and EJB JAR file, because this may cause class cast exceptions, if the two class loaders,end up independently loading one or more classes.

Thus there are two basic problems relating to J2EE class loading, in the common case where EJB and web modules are included in the same enterprise application:

  • Where do we hold the definitions of classes used in both EJBs and web applications?

  • How do we ensure that two class loaders don't end up holding independent versions of the same class, resulting in class cast exceptions?

The Servlet 2.3 Specification's Class Loading Recommendations

Not only do implementations of class loading differ, but different J2EE specifications differ regarding class loading.

The Servlet 2.3 specification (9.7.2) states that "It is recommended also that the application class loader be implemented so that classes and resources packaged within the WAR are loaded in preference to classes and resources residing in container-wide library JARs".

This clearly conflicts with the standard J2SE class loading behavior, as described in the Javadoc for the java.lang.classLoader class. As the WAR class loader must be a dynamic class loader, it must be the child of another class loader provided by the application server. Hence the Servlet 2.3 recommendation is the opposite of normal Java 2 class loading behavior, which clearly states that classes will be loaded from the child class loader (in this case the WAR class loader) only if they cannot be resolved by the ancestor class loaders.

This recommendation (note that it is not a requirement) is also unclear on where EJBs fit into the proposed class loading model. EJBs are presumably not considered to be "classes and resources residing in containerwide library JARs"*, in which case the requirement does not apply to them.

The contradiction between the Servlet 2.3 and normal Java 2 class loading behavior is underlined by the fact that Sun's J2EE 1.3 Compatibility Test Suite fails on servers that default to implementing Servlet 2.3-style inverted class loading. For this reason, many servers either don't implement the Servlet 2.3 recommendation, or offer it only as a configuration option. The JBoss/Jetty bundle used in the sample application defaults to using normal Java 2 class loading behavior, although it can be configured to use Servlet 2.3 WAR-first behavior. Oracle iAS takes the same approach.

The main merit of Servlet 2.3-style class loading is that it can allow us to ship any patched libraries an application requires as part of the application, without altering the server installation. For example, the XMLC 2.1 web content generation technology discussed in Chapter 13 requires patched versions of XML libraries shipped with some application servers. With Servlet 2.3 class loading, we can include the necessary patches in the /WEB-INF/lib directory, without any need to modify overall server configuration or any risk of conflict with other applications.

The Java 1.3 Extension Mechanism Architecture in J2EE

We also need to take into account further J2SE class loading refinements. Changes inJ2SE 1.3 make it possible for JAR files to specify dependencies on other JAR files, by specifying a space-separated list of relative file paths in a Class-Path header in their /META-INF/MANIFEST.MF file. Section 8.1.1.2 of the J2EE 1.3 specification requires that application servers support this for EJB JAR files. The following example from the sample application's ticket-ejb.jar file's MANIFEST.MF file illustrates the use of this mechanism in the sample application:

   Class-Path: log4j-1.2.jar i21-core.jar i21-ejbimpl.jar i21-jdbc.jar 

This declares that the application-specific classes in the ticket-ejb.jar file depend on four infrastructure JARs, meaning that the EJBJAR file doesn't need to include any third party classes. These paths are relative. All these JAR files are included with the EJBJAR file in the root directly of the application EAR, as the following listing of the EAR's contents shows:

    META-INF/    META-INF/MANIFEST.MF    META-INF/application.xml    i21-core.jar    i21-ejbimpl.jar    i21-jdbc.jar                                                                                                                 ticket-ejb.jar    ticket.war    log4j-1.2.jar                                                                                                             

Some application servers support the manifest classpath mechanism for WAR and EAR deployment units, but as these are not loaded directly by class loaders this is not required byJ2SE 1.3 or theJ2EE 1.3 specification. For example, see documentation at http://otn.oracle.com/tech/java/oc4j/htdocs/how-to-servlet-warmanifest.html on how to enable WAR manifest classpaths on Oracle 9iAS Release 2. (This support is disabled by default.) WebSphere 4.0 also supports manifest classpaths for WAR files, and IBM documentation (see http://www3.ibm.com/software/webservers/appserv/doc/v40/aee/wasa_content/06040.ibm.com/software/webservers/appserv/doc/v40/aee/wasa-content/060401.html) recommends using this when WARs and EJBs reference the same classes. Orion and Oracle will also load manifest classpaths in EARs by default. Note that JBoss/Jetty does not appear to respect manifest classpaths in WARs, so I haven't relied on this non-portable feature in packaging the sample application. The J2EE Reference Implementation also ignores manifest classpaths in WARs.

The Servlet 2.3 specification requires that web containers respect the manifest classpaths of library files included in a web application's /WEB-INF/lib directory. However, this is problematic in integrated EAR deployment, as it's unclear what the relative path should be where a WAR is involved. What is the meaning of a relative path from a nested directory inside an archive file? For example, if a . war file is included in the root directory of an EAR, along with the EJBJAR files it references, which of the following two plausible relative paths should libraryJARs use?

  • ../ .. /other-jar-file .jar, which navigates to the WEB-INF directory and then the root of the WAR, and assumes that the library JAR(s) are in the same directory as the root of the WAR.

  • ../../.. /other-jar-file .jar, which navigates one directory higher, assuming that the .war file will have been extracted into its own directory under the root of the EAR, an approach that most servers will use.

Neither alternative works in JBoss/Jetty. Thus using manifest classpaths in JARs in a /WEB-INF/lib directory is not portable. Perhaps for this reason, the J2EE 1.3 specification (section 8.1.1.2) suggests that it is necessary to include shared libraries in the /WEB-INF/lib directory even if they are included elsewhere in the same EAR file.

Section 8.1.1.2 of theJ2EE specification does not require the resolution of classes external to the EAR file, such as libraries installed at a server level. This may work in some servers, but is non-standard. If an application depends on external binaries, it's usually better just to use your server's way of installing binaries at server-wide level. (This is also non-portable, but simpler).

Despite these limitations, the J2SE Extension Mechanism Architecture has important implications for J2EE application packaging. It allows an approach to J2EE packaging in which we use multiple JAR files to avoid the need to include the same class definitions in multiple modules within an EAR. This is particularly important when application classes depend on in-house or third-party libraries. For example, we can use JAR files containing library classes required by multiple EJBs, while EJB JAR files contain only applicationspecific EJB implementation classes. See http://www.onjava.com/lpt/a/onjava/2001/06/26/ejb.html for an article by Tyler Jewell of BEA discussing the use of manifest classpaths.

Important 

Especially in EJB JAR files, use J2SE 1.3 manifest classpaths to avoid the need to include the same class definitions in multiple modules. However, remember that not all application servers support manifest classpaths in EAR or WAR deployment units. Also, remember that manifest classpaths only affect where a class definition is held, and do not resolve problems resulting from which class loader first loads a class (for example, the problem of a class loaded by an EJB class loader being unable to see classes within a WAR in many servers).

Thread Context Class Loader

It's also possible to try to resolve class loading problems by using the Java Thread API to obtain a class loader programmatically. Section 6.2.4.8 of theJ2EE 1.3 specification requires allJ2EE containers to support the use of the getContextClassLoader() method on java.util.Thread.

The J2EE specification isn't entirely clear regarding context class loading. However, the intent appears to be to allow portable classes, such as value objects, to load application classes in whatever container (such as EJB or web container) they may run in. In practice, the context class loader appears to be in the context of the current container. To clarify this behavior, let's consider the effect of the following two calls, made by a helper class that is loaded by the EJB class loader but used in both EJBs and classes running in the web container:

  • Class.forName (classname): Will use the class loader of the helper class: in this case, the EJB class loader. This means that, if the EJB class loader is the parent of the WAR class loader, the helper will never be able to load classes in the WAR by name.

  • Class.forName(classname, true, Thread.currentThread().getContextClassLoader()): Will use the current container's class loader. This means that the helper will behave differently wherever it is running. If the EJB class loader is the parent of the WAR class loader, when the helper is used in the EJB container, it will only be able to load EJB classes and classes loaded by higher class loaders. If the helper is used in the WAR, it will be able to load WAR classes as well.

Many frameworks, such as WebWork, use this approach to avoid problems caused by hierarchical class loading. However, it's not usually required in application code, which should normally only load classes by name using an abstraction layer that should conceal any use of the context class loader.

Server Check List

As no two servers implement class loading in exactly the same way, and class loading behavior can even change between successive releases of the same server, let's conclude with a check list of things that you should find out to understand class loading in your application server:

  • What is your server's runtime class hierarchy? For example, is the EJB class loader the parent of the WAR class loader?

  • Does your server support Servlet 2.3-style class loading (WAR first) for web applications?

  • Does your server provide manifest classpath support for EAR and WAR deployment units, not merely JARs such as EJB JAR files? If so, is it necessary to change server configuration to enable it?

  • Is your server's class loading behavior fixed, or is it possible to configure it? In some servers, for example, it's possible to choose between normal Java 2 and Servlet 2.3 class loading behavior.

  • What is the relationship, if any, between classes in different applications deployed on the same server? In JBoss 3.0, for example, which uses an unusual, flat, class loader structure, special configuration is required to deploy two different versions of the same class on the same server (otherwise the two versions of the class will conflict). In many other servers, different applications will be entirely independent.

Recommendations

Although the different behavior of different application servers makes it impossible to advance hard and fast rules where packaging and class loading are concerned, I recommend the following guidelines:

  • Only include application-specific classes in EJB JAR files and
    /WEB-INF/classes directories
    EJB JAR files that depend on reusable infrastructure classes should use manifest classpaths to indicate their dependency on other classes within the EAR.

  • Binaries required only by a web application should be included in the
    /WEB-INF/lib directory
    In pure web applications, simply include all required JAR files in this directory.

  • Binaries used by both EJBs and web applications should be included in JAR files in application EARs
    If your application server supports manifest classpaths for WARs, these can be used to declare a dependency on the JAR files in the EAR. If your application server doesn't support this, the JAR files will also need to be included in the /WEB-INF/lib directory of each WAR module. This duplication is unfortunate, but theJ2EE 1.3 specification implies that it is necessary for portable applications.

  • Consider the implications of loading classes by name carefully
    Try to ensure that classes that load other classes are by name are loaded only by the class loader of the module they will be used in (for example, it is possible to use distinct subclasses of a common superclass when similar functionality is required in a WAR and EJB JAR). Alternatively, you may be able to use the thread context class loader to get a class loader to load classes with. This problem should normally be concealed by infrastructure classes, and thus shouldn't normally affect application code.

  • Server-wide classes such asJDBC drivers and JDO implementations should be installed in at server, not application level
    For example, in JBoss 3.0 such JARs or zips can be placed in the /lib directory of the current server; in Orion, they can be placed in Orion's /lib directry. This approach can sometimes be used to solve problems with application-specific class loading (for example, to guarantee that certain application classes are availble in all modules of an application), but it's an inelegant last resort. It means that the application server can't dynamically reload these classes, and that deployment units are no longer self-contained, which violates the J2EE specifications.

  • If necessary, run tests to establish the class loader hierarchy of your application server
    The com.interface21.beans.ClassLoaderAnalyzer class in the infrastructure included with the sample application contains methods to show the class loader hierarchy for a given class or ClassLoader. I've found such diagnostics very useful in tracking down class loading problems.

Important 

In complex applications, it can be difficult to devise packaging that is portable across application servers. In some cases portable packaging may add little business value, but may be very time-consuming to achieve.

Concentrate on the target application server when packaging applications. But remember the issues discussed above, and especially the likely implications of hierarchical class loaders in applications using EJBs.

Further Information

J2EE class loading is a very complex topic. See the following resources for further information:

  • http://kb.atlassian.com/content/atlassian/howto/classloaders.jsp. Clear, concise description of Orion server's class loading behavior, with references to other resources.

  • http://www.javageeks.com/Papers/ClassForName/index.html. Excellent, detailed discussion of Java 2 class loading behavior, with some (now dated) reference to J2EE.

  • http://www.theserverside.com/resources/articles/ClassLoading/article.html. Article on application server class loading article by Brett Peterson, which discusses the implementations in WebLogic 6.1, WebSphere 4.0 and HP-AS 8.

  • Your application server's documentation. This is usually the most important resource. If it's not entirely clear, run a diagnostic tool such as the com.interface21.beans.ClassLoaderAnalyzer class included in the download to display the server's class loader hierarchy.

Packaging the Sample Application

The sample application isn't distributed, and contains a web application and one EJB. Thus we will need to create WAR, EJB JAR, and EAR deployment units, and the application will normally be deployed as an EAR. We use Ant to build each of these deployment units.

First we need to understand how to package the generic infrastructure classes the application uses, which may also be used in other applications. As the infrastructure discussed in Chapter 9, Chapter 11, and Chapter 12-notably, the bean factory andJDBC abstraction packages-is used in both EJBs and web components and needs to load classes by name, it's important that it can be packaged so as not to complicate application specific class loading.

Thus the framework classes discussed in this book are packaged in four separate JAR files, which can be included in application deployments and referenced usingJ2SE 1.3 manifest classpaths. The implementation and packaging of this framework takes care to ensure that class loading by name will work, even in application servers that use complex class loader hierarchies.

The framework classes are divided into the following JARs, built by the /framework/build.xml file in the download, which is invoked by the sample application's build.xml file in the download's root directory. You should adopt a similar multi-JAR strategy if you create your own library packages for use across multiple applications:

  • i21-core.jar

    Core framework packages including the com. interface21. beans package discussed in Chapter 11; logging support and nested exceptions discussed in Chapter 4; string, JNDI and other utility classes. None of these classes loads other classes by name, although subclasses of some of them will. This JAR file will be used in both EJBs and web applications. All other JAR files depend on the classes in this JAR.

  • i21-web.jar

    Framework packages required only in web applications, which should be included only in the /WEB-INF/lib directory of WAR files. This JAR includes:

  • Bean factory implementations used only in web applications, such as com.interface21.beans.factory.support.XmlBeanFactory. Since these implementations are loaded by the WAR class loader, not the EJB class loader, they are guaranteed to be able to see application classes included in the WAR.

  • The "application context" infrastructure discussed in Chapter 11, which isn't required by EJBs.

  • The MVC web framework discussed in Chapter 12, including custom tags and validation infrastructure.

  • EJB client classes, such as superclasses for business delegates and service locators.

  • JMS abstraction classes. These are never required in EJBs, as we can use MDBs to solve the same problems in a standard way.

  • i21-ejbimpl.jar

    EJB superclasses and the JNDI bean factory implementation, which is not used by WARs, and so can be loaded by the EJB class loader.

  • i21-jdbc.jar

    The JDBC abstraction layer and generic data access exception packages discussed in Chapter 9. The classes in this JAR do not use reflection, and are likely to be used by both web applications and EJBs.

All that we need to do to assemble an application is to ensure that the necessary JARs are available to EJB and WAR modules. The same Interface21 JARs required to compile application-specific classes must be available to the relevant deployment unit at runtime.

The EAR will contain all the infrastructure JARs except i21-web.jar in the root directory, as follows:

    META-INF/    META-INF/MANIFEST.MF    META-INF/application.xml    i21-core.jar    i21-ejbimpl.jar    i21-jdbc.jar                                                                                                                 ticket-ejb.jar    ticket.war    log4j-1.2.jar 

The EJB JAR module uses a manifest classpath declaring its dependence on i21-core.jar, i21-ejbimpl.jar and i21-jdbc.jar, as we've seen above:

    Class-Path: log4j-1.2.jar i21-core.jar i21-ejbimpl.jar i21-jdbc.jar                                                       

The WAR includes i21-core.jar, i21-web, jar and i21-jdbc.jar in its /WEB-INF/lib directory, as the following partial listing of its contents shows:

    WEB-INF/lib/log4j-1.2.jar    WEB-INF/lib/jstl.jar    Other library classes omitted    WEB-INF/lib/i21-core.jar    WEB-INF/lib/i21-jdbc.jar    WEB-INF/lib/i21-web.jar                                                                                                   

In a server such as Orion or WebLogic, in which the EJB class loader is the parent of the WAR class loader,we would only need to include i21-web.jar here. However, in JBoss, which does not use this hierarchicalclass loading structure, all these JARs are required. If we knew that our server supported manifest classpathsin WARs, we could simply declare a manifest classpath in the WAR.

The ticket-ejb.jar file and the /WEB-INF/classes directory of the WAR will contain only application-specific classes.

Now that we know what must go into our deployment units, we can write Ant scripts to build them.

Ant provides useful standard tasks to build WAR and EAR deployment units. The war task is an extension of the jar task, allowing easy selection of deployment descriptors destined for the WAR's WEB-INF directory, JAR files destined for the WEB-INF/lib directory and application classes destined for the /WEB-INF/classes directory. The webxml attribute of the <war> element selects the standard deployment descriptor; the <webinf> sub-element selects other files, such as proprietary deployment descriptors, for inclusion in the /WEB-INF directory; while <lib> and <classes> sub-elements select binaries and classes respectively.

The following is the target used in the sample application:

    <target name="war" depends="build-war">
           <war warfile="${web-war.product}"                 webxml="${web-war.dir}/WEB-INF/web.xml">

                 <fileset dir="${web-war.dir}" excludes="WEB-INF/**"/>                 <webinf dir="${web-war.dir}/WEB-INF">                         <exclude name="web.xml"/>                 </webinf> 

Here we ensure that application-specific classes, compiled into the directory specified by the classes. dir Ant property, go into the /WEB-INF/classes directory:

    <classes dir="${classes.dir}">             <include name="**/* .class"/>    </classes> 

I've used several <lib> sub-elements of the <war> element to select the runtime libraries required for the different view technologies demonstrated in Chapter 13, as follows:

           <lib dir="${lib. dir}/runtime/common" />           <lib dir="${lib. dir}/runtime/jsp-stl" />           <lib dir="${lib. dir}/runtime/velocity" />           <lib dir="${lib. dir}/runtime/xmlc" />           <lib dir="${lib. dir}/runtime/itext-pdf" /> 

The following subelement includes the Interface21 infrastructure JARs in the /WEB-INF/lib directory. If the application server supported manifest classpaths for WARs, we could omit the first two of these JARs, and provide a manifest referring to these JARs in the WAR's root directory:

           <lib dir="${dist.dir}">                      <include name="i21-core.jar"/>                      <include name="i21-jdbc.jar"/>                      <include name="i21-web.jar"/>             </lib>       </war> </target> 

The Ant EAR task is also easy to use. We simply need to specify the location of the application.xml deployment descriptor and specify the archives to be included using <fileset> sub-elements. In the sample application's directory layout, the deployment descriptor is in the /ear directory, and the WAR and EJB JAR files are in the /dist directory. Note that this task depends on the EJB JAR file and WAR being up to date:

    <target name="ear" depends="ejb-jar, war">            <ear earfile="${app-ear. product}" appxml="ear/application.xml">                 <fileset dir="${dist. dir}">                          <include name="ticket.war"/>                          <include name="ticket-ejb.jar"/> 

We include the EJB JAR file's dependencies in the root directory of the WAR:

                   <include name="i21-core.jar"/>                   <include name="i21-ejbimpl.jar"/>                   <include name="i21-jdbc.jar"/>                      </fileset>                            <fileset dir="lib/runtime/common">                            <include name="log4j*.jar"/>                      </fileset>              </fileset>        </ear> </target> 

The optional Ant EJB tasks are less useful, at least in my experience. Unlike WAR and EAR deployment units, EJB JAR files are ordinary JAR files, with deployment descriptors in the /META-INF directory. Accordingly, I've used the standard jar task to generate the EJB JAR file. This is simply a matter of specifying the contents of the /META-INF directory of the generated JAR file (the standard ejb-jar.xml and any proprietary deployment descriptors) and selecting the classes by setting the basedir attribute to the root of the directory containing the compiled application-specific EJB classes:

    <target name="ejb-jar" depends="build-ejb">
           <jar jarfile="${ejb-jar. product}"                   basedir="${ejbclasses. dir}"                   manifest="${ejb-jar. dir}/manifest"            >            <metainf dir="${ejb-jar.dir}">                          <include name="*/**"/>            </metainf>            </jar>    </target> 

Note the use of the manifest attribute of the jar task, which specifies the file to use as the JAR's manifest, enabling us to specify the manifest classpath shown above.

Like the WAR target, this EJB target takes all files from the deployment descriptor directory, not just ejb-jar.xml. Proprietary deployment descriptors, such as jboss.xml or weblogic-ejb-jar.xml must also be included in the deployment unit.

Important 

To use the library classes included in this book in your own applications, you will need to include i21-core.jar and either i21-ejbimpl.jar or i21-web.jar, depending on whether you're implementing EJBs or a web module. Note that i21-web.jar should be included in a /WEB-INF/lib directory: it should not be loaded by an EJB class loader. If using the JDBC abstraction described in Chapter 9, which can be used in both EJBs and web applications, i21-jdbc.jar is required.

All these JAR files are found in the /dist directory of the download. The complete Ant build file discussed above is named build.xml in the root directory of the download.



Expert One-on-One J2EE Design and Development
Microsoft Office PowerPoint 2007 On Demand
ISBN: B0085SG5O4
EAN: 2147483647
Year: 2005
Pages: 183

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net