16

I've used the maven-ear-plugin with the maven-war-plugin and maven-ejb-plugin to successfully deploy and run an application packaged as EAR to Jboss AS7.

.
|-- META-INF
|   |-- application.xml
|   |-- MANIFEST.MF
|   `-- maven
|       `-- com.patrac
|           `-- Patrac-ear
|               |-- pom.properties
|               `-- pom.xml
|-- Patrac-ejb-1.0-SNAPSHOT.jar
`-- Patrac-web-1.0-SNAPSHOT.war

In the application source code directories, the poms are located as follows:

.
|
|-- Patrac-ear
|   `-- pom.xml
|-- Patrac-ejb
|  `-- pom.xml
|-- Patrac-web
|   `-- pom.xml
`-- pom.xml

I can't figure out how to stop a few annoying warning messages when I deploy the application:

12:32:03,958 WARN  [org.jboss.as.server.deployment] (MSC service thread 1-2) Class Path entry richfaces-components-ui-4.0.0.Final.jar in "/content/Patrac.ear/Patrac-web-1.0-SNAPSHOT.war"  does not point to a valid jar for a Class-Path reference.
12:32:03,970 WARN  [org.jboss.as.server.deployment] (MSC service thread 1-2) Class Path entry richfaces-components-api-4.0.0.Final.jar in "/content/Patrac.ear/Patrac-web-1.0-SNAPSHOT.war"  does not point to a valid jar for a Class-Path reference.
12:32:03,984 WARN  [org.jboss.as.server.deployment] (MSC service thread 1-2) Class Path entry richfaces-core-api-4.0.0.Final.jar in "/content/Patrac.ear/Patrac-web-1.0-SNAPSHOT.war"  does not point to a valid jar for a Class-Path reference.
12:32:03,989 WARN  [org.jboss.as.server.deployment] (MSC service thread 1-2) Class Path entry richfaces-core-impl-4.0.0.Final.jar in "/content/Patrac.ear/Patrac-web-1.0-SNAPSHOT.war"  does not point to a valid jar for a Class-Path reference.

Patrac-web-1.0-SNAPSHOT.war!META-INF/MANIFEST.MF looks like this:

Manifest-Version: 1.0
Built-By: pgarner
Build-Jdk: 1.7.0_02
Class-Path: Patrac-ejb-1.0-SNAPSHOT.jar richfaces-components-ui-4.0.0.
 Final.jar richfaces-components-api-4.0.0.Final.jar richfaces-core-api
 -4.0.0.Final.jar richfaces-core-impl-4.0.0.Final.jar cssparser-0.9.5.
 jar sac-1.3.jar guava-r08.jar
Created-By: Apache Maven
Archiver-Version: Plexus Archiver

The ejb class-path entry needs to be present for the EJB module, for portability, and the richfaces, cssparser and guava class-path entries should NOT be in the WAR's manifest.

The problem is that my WAR depends on all of the JARs, some of which live in WEB-INF/lib (RichFaces), and one JAR, Patrac-ejb-1.0-SNAPSHOT.jar, that lives in the root directory of the EAR. Each dependency needs to be entered in Patrac-web/pom.xml but NOT each of the dependencies should appear in the manifest.

Maven puts the JARs in the correct places, but it puts Class-Path entries for ALL of the JARs into the manifest. It should not do this. It should ONLY put an entry in for Patrac-ejb-1.0-SNAPSHOT.jar.

  <!--
    According to Java EE 6 spec, the application is portable if
    Patrac-web.war's META-INF/MANIFEST.MF contains a Class-Path entry
    for Patrac-ejb-1.0-SNAPSHOT.jar.

    <optional>true</optional> is the flag that maven-war-plugin uses
    to put the entry in MANIFEST.MF without copying Patrac-ejb-1.0-SNAPSHOT.jar
    into WEB-INF/lib.  This is what I want.

    <scope>provided</scope> would cause maven-war-plugin to NEITHER
    put the entry in MANIFEST.MF nor copy Patrac-ejb.jar into WEB-INF/lib,
    which would not be good.

    No tag at all would cause maven-war-plugin to BOTH put the entry in
    MANIFEST.MF and copy Patrac-ejb.jar into WEB-INF/lib, which would
    also not be good.
  -->
  <dependency>
     <groupId>com.patrac</groupId>
     <artifactId>Patrac-ejb</artifactId>
     <type>ejb</type>
     <optional>true</optional>
  </dependency>

  <!--
   These two dependencies are used to copy
  the other JAR files into WEB-INF/lib and there
  should not be any class-path entries for such
  JARs in MANIFEST.MF, in order to avoid the
  error messages.
  -->
    <dependency>
        <groupId>org.richfaces.ui</groupId>
        <artifactId>richfaces-components-ui</artifactId>
    </dependency>
    <dependency>
        <groupId>org.richfaces.core</groupId>
        <artifactId>richfaces-core-impl</artifactId>
    </dependency>

I'm using the most recent maven-war-plugin version, 2.2. How do I tell the maven-war-plugin to put the "non-ejb" JARs into WEB-INF/lib while not putting class-path entries in MANIFEST.MF?

Any advice or pointers you have are greatly appreciated.

References:

Arjan Tijms
  • 36,666
  • 12
  • 105
  • 134
Patrick Garner
  • 3,003
  • 6
  • 35
  • 55

4 Answers4

21

The Maven archiver, used by the Maven WAR plugin, provides a means to generate Class-Path entries in the WAR's manifest but unfortunately the archiver takes an all-or-nothing approach. Once you pass addClassPath=true to the archive configuration, the archiver puts Class-Path entries for all of the WAR's required- and optional dependencies into the manifest.

However, some entries simply do not belong in there. Class-Path entries are used to denote "Download Extensions," or references to JARs external to the WAR. JARs located in WEB-INF/lib should not, therefore, have Class-Path entries in the WAR's manifest. Maven's War plugin breaks this rule when you set addClassPath=true in the archiver.

Moreover, when you pass addClassPath=true to Maven's archiver, it gives all of the Class-Path entries the same directory prefix -- no matter where the dependencies are located within the EAR. This causes problems when optional- and required dependencies are located in separate locations such as the EAR root directory, EAR lib and WAR WEB-INF/lib.

Naturally, when one deploys an EAR whose WAR manifest contains the above errors JBoss throws warnings if the WAR class loader can ultimately find a dependency (JARs located in WEB-INF/lib) or errors if the class path prefix is wrong (e.g. on an EJB JAR or a dependency in the EAR lib directory).

Therefore, if your WAR, like mine, depends on an EJB module, located at the root of the EAR, and any number of dependencies that are located inWEB-INF/lib, Maven archiver will generate Class-Path entries for all of the dependencies and they will all have the same prefix regardless of their location within the EAR.

Not good.

The problem would be ameliorated somewhat if the archiver would provide a means to exclude Class-Path entries of the JARs located in WEB-INF. But it does not.

Here's a summary of the outcome for each dependency setting when one uses addClassPath=true:

           Setting                  Generate               Copy JAR into
                                   Class-Path              WEB-INF/lib
                                     Entry

1.  <scope>provided</scope>             NO                      NO

2.  <optional>true</optional>          YES                      NO

3.  (no option -- default)             YES                     YES

4.  ?????                               NO                     YES

What is needed is coverage for situation #4, above: do not create a Class-Path entry and, yes, do copy the JAR into WEB-INF/lib. Maven archiver should implement this behavior by default.

The best solution I can think of is to use brute force and turn off the Maven archiver's automatic Class-Path entry generation. Instead, I explicitly create a Class-Path entry for the EJB module in the WAR's manifest using the archiver's manifestEntries option. The way to do this is to remove the following from Patrac-web/pom.xml:

<manifest>
    <addClasspath>true</addClasspath>
</manifest>

and replace it with this:

<manifestEntries>
    <Class-Path>Patrac-ejb-${project.version}.jar</Class-Path>
</manifestEntries>

Using this configuration only one Class-Path entry, for the EJB module, is created explicitly.

Patrick Garner
  • 3,003
  • 6
  • 35
  • 55
1

For those JARs with need to be excluded from MANIFEST and from WEB-INF/lib you need to mark them as <scope>provided</scope>. That means JAR files will be provided by the container (and that is EAR in your case).

For other options check WAR manifest guide.

dma_k
  • 9,513
  • 13
  • 68
  • 122
  • 1
    The [War manifest guide](http://maven.apache.org/plugins/maven-war-plugin/examples/war-manifest-guide.html) shows 3 examples and provides a note: "No way is shown how to include a dependency in WEB-INF/lib but not in the manifest classpath." The Guide then says, "Check the [Guide to Working with Manifests](http://maven.apache.org/guides/mini/guide-manifest.html) for more examples." This second page simply refers me back to the WAR manifest guide page. I need to be able to follow the example that's not shown. – Patrick Garner Feb 13 '12 at 19:19
  • You want to include a dependency in WEB-INF/lib but not in the manifest classpath? Why you need that? If your `richfaces`, `cssparser` and `guava` leave in EAR, then these dependencies should be marked as `provided`. – dma_k Feb 13 '12 at 20:55
  • Richfaces et al are required dependencies of the WAR module. Thus, they should be in WEB-INF/lib. My understanding is that no Class-Path entries need to be made for JARs in WEB-INF because such files are automatically loaded by the WAR's class loader. Only Class-Path entries for JARs _external_ to the WAR module need to be entered in the WAR's manifest. In my case, an entry must be made for the EJB JAR. This is per JEE spec. RichFaces et al are required dependencies of the WAR module and thus should not be marked as `provided`. – Patrick Garner Feb 14 '12 at 03:38
  • So, everything works fine. It's just that the RichFaces dependencies should not have Class-Path entries in the WAR's manifest. When the Class-Path entries are present, WARNING messages occur during deployment. JBoss complains that it can't find the RichFaces dependencies in the global EAR directory because it reads the Class-Path entries from the manifest that maven-war-plugin put there. However, the application runs fine because JBoss automatically finds the RichFaces JARs in WEB-INF/lib. JARs in WEB-INF/lib should NOT have Class-Path entries in the manifest. – Patrick Garner Feb 14 '12 at 04:09
  • **Patrick**, I do not fully agree with you. If `richfaces` et al are required dependencies for WAR, thay not necessarily need to be in `WEB-INF/lib` and [`servlet-api`](http://stackoverflow.com/questions/1979957) is a good example of that. If your jars are provided by container (and EAR is in your case the container for WAR), than you mark them as `provided`. Thus they are not in `WEB-INF/lib` and not in Class-Path (but are packaged as part of `Patrac-ear`). I see this as most correct way. – dma_k Feb 14 '12 at 21:38
  • no no that's incorrect. `servlet-api` is a reference implementation of the JEE spec. required to be provided by certified application servers (JBoss, Glassfish, Weblogic, etc.). Conversely, RichFaces is not a reference implementation that comes included. Facelets in my WAR are dependent on it. Adding it as a dependency in the WAR's POM causes Maven to copy RichFaces JAR into WEB-INF/lib and not add a Class-Path entry in the WAR's manifest, which is correct. The EAR is not a container. Rather, it's a JAR used to package the modules that are deployed to the containers. – Patrick Garner Feb 15 '12 at 03:17
  • RichFaces is not part of the spec. [Read it for yourself](http://en.wikipedia.org/wiki/Java_EE_version_history#Java_EE_6_.28Dec_10.2C_2009.29). The problem is that Maven has issues with EAR deployment that need to be worked out. Namely, providing a way to properly manage Class-Path entries in the WAR's manifest when both EJB modules and non-JEE-spec. dependencies coexist in the same deployment. – Patrick Garner Feb 15 '12 at 03:32
  • `provided` scope does not necessarily mean that the dependency should be a part of J2EE spec. For example `tools.jar` can be `provided` (in case we are sure we deploy to Sun JVM). EAR of course strictly speaking can't be called a container, but from [classloader perspective](http://lowerthan60.files.wordpress.com/2010/06/j2eecl.png) it is. If jars are provided somewhere above in the hierarchy, at at all lower levels the dependency is `provided`. Well, you can not agree with is. But how do you mark you Richfaces dependencies, if you copy jars to `server/lib` folder? – dma_k Feb 15 '12 at 21:58
  • 1
    the EAR is not a JEE container, even from the class loader perspective! If you want to understand how the class loading works in JEE, read the JEE spec. tools.jar has NOTHING to do with this discussion! RichFaces SHOULD NOT GO INTO server/lib, EVER, not even to try to make a point! End of discussion. Your posts are ridiculous and unhelpful. Please stop. – Patrick Garner Feb 16 '12 at 02:27
0

The ejb class-path entry needs to be present for the EJB module …

The class-path only needs to be present for EJBs modules (in the root of the EAR) who reference other EJB modules (in the root of the same EAR)

Philippe Marschall
  • 4,277
  • 1
  • 27
  • 48
0

read specifically about skinny wars

http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html

Kalpesh Soni
  • 5,577
  • 2
  • 44
  • 51