Maven 2.x WAR Plugin

WAR plugin should support minimal WARs for inclusion within an EAR

Details

  • Type: Improvement Improvement
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Won't Fix
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None
  • Number of attachments :
    1

Description

I noticed that when I build a WAR, I get a gigantic WEB-INF/lib with all my deps. This is fine for a default but maven should also support "skeleton" WARs which will be packaged within an EAR. We have EARs which package 3-4 WARs each and to have the deps duplicated within each WAR means we cannot have shared data (since the classes are loaded within each WAR's classloader, rather than by the parent EAR's classloader). It also means 80MB EARs!

It seems like two things need to happen:

1) Add a "skeleton" flag which prevents copying any dependencies to WEB-INF/lib.
2) Instead generate a META-INF/MANIFEST.MF which has a Class-Path entry which lists the relative locations of the dependencies within the parent EAR.

Fabrice has basically the same idea written down here. Starting with "- for a War..." : http://marc.theaimsgroup.com/?l=turbine-maven-user&m=112737860024530&w=2

Issue Links

Activity

Hide
Mike Perham added a comment -

Patch to WarMojo to add "earPackaged" boolean. Second block is all messed up - it's just an if() statement around the artifact packaging.

Show
Mike Perham added a comment - Patch to WarMojo to add "earPackaged" boolean. Second block is all messed up - it's just an if() statement around the artifact packaging.
Hide
Mike Perham added a comment -

Note that when you use the attached patch, your WAR project must have a pre-generated MANIFEST.MF with a Class-Path entry. It appears that Plexus Archiver overwrites this MANIFEST when it packages the WAR so this will need to be fixed to allow custom MANIFEST.MFs.

Show
Mike Perham added a comment - Note that when you use the attached patch, your WAR project must have a pre-generated MANIFEST.MF with a Class-Path entry. It appears that Plexus Archiver overwrites this MANIFEST when it packages the WAR so this will need to be fixed to allow custom MANIFEST.MFs.
Hide
Mike Perham added a comment -

This is more of a documentation issue than anything. The EAR and WAR plugins already support the features required to move ALL war dependencies to the EAR with some caveats. This is the email I sent to the user list today:

We throw everything in <EAR_ROOT>/lib and exclude them from WEB-INF/lib. The WAR's MANIFEST.MF is autogenerated like so:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warSourceExcludes>WEB-INF/lib/*.jar</warSourceExcludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>

In the EAR's POM, you need to list all the dependencies that the WARs have as direct dependencies in the EAR. This will tell the plugin to copy all dependent jars to <EAR_ROOT>/lib.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
<defaultJavaBundleDir>lib/</defaultJavaBundleDir>
</configuration>
</plugin>

Show
Mike Perham added a comment - This is more of a documentation issue than anything. The EAR and WAR plugins already support the features required to move ALL war dependencies to the EAR with some caveats. This is the email I sent to the user list today: We throw everything in <EAR_ROOT>/lib and exclude them from WEB-INF/lib. The WAR's MANIFEST.MF is autogenerated like so: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <warSourceExcludes>WEB-INF/lib/*.jar</warSourceExcludes> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> </manifest> </archive> </configuration> </plugin> In the EAR's POM, you need to list all the dependencies that the WARs have as direct dependencies in the EAR. This will tell the plugin to copy all dependent jars to <EAR_ROOT>/lib. <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ear-plugin</artifactId> <configuration> <defaultJavaBundleDir>lib/</defaultJavaBundleDir> </configuration> </plugin>
Hide
David Boden added a comment -

>> In the EAR's POM, you need to list all the dependencies that the WARs have as direct dependencies in the EAR. This will tell the plugin to copy all dependent jars to <EAR_ROOT>/lib.

I've got a fairly complex project that requires packaging as an EAR. It's not really practical to do this. I picked Maven, after all, because of its advanced transitive dependency support.

The ear plugin should take all the <type>war</type> dependencies and transitively work out its subdependencies. There should be an option to then package these dependencies into the EAR.

Show
David Boden added a comment - >> In the EAR's POM, you need to list all the dependencies that the WARs have as direct dependencies in the EAR. This will tell the plugin to copy all dependent jars to <EAR_ROOT>/lib. I've got a fairly complex project that requires packaging as an EAR. It's not really practical to do this. I picked Maven, after all, because of its advanced transitive dependency support. The ear plugin should take all the <type>war</type> dependencies and transitively work out its subdependencies. There should be an option to then package these dependencies into the EAR.
Hide
Mark Chesney added a comment -

I have a patch which is attached to MWAR-21 which supports a minimal type WAR packaging within an EAR. See http://jira.codehaus.org/browse/MWAR-21 . It does not support a combination of EAR and WEB-INF/lib dependencies, just one or the other.

Show
Mark Chesney added a comment - I have a patch which is attached to MWAR-21 which supports a minimal type WAR packaging within an EAR. See http://jira.codehaus.org/browse/MWAR-21 . It does not support a combination of EAR and WEB-INF/lib dependencies, just one or the other.
Hide
Al Robertson added a comment -

Comment taken from on MWAR-21

Here is a structure that J2EE requires maven to support

ear
---jar1
---war ->manifest classpath:jar1
-------jar2

war depends on jar1 and jar2

Currently, you can specify to add a manifest classpath entry. This adds an entry for each dependency that is not "Provided", because provided means "provided by the container". (CORRECT)
In the above example, I can't configure maven to exclude jar1 from the war/WEB-INF/lib dir but include it in the classpath manifest.

It appears to me that we need another dependency attribute to accompany scope "Provided", say <providedByManifestClasspath>true</providedByManifestClasspath> or a <providedBy>CONTAINER|MF-CP</providedBy> etc.
In this solution, we wouldn't need the manifest->addClasspath plugin config. The war builder would only include the artifact in the war when the scope wasn't provided and the war archiver would know when to include the dependency in the manifest classpath.
You would still require the manifest classpath prefix config.

Does this make sense?
Is there a way to accomplish this already?

Show
Al Robertson added a comment - Comment taken from on MWAR-21 Here is a structure that J2EE requires maven to support ear ---jar1 ---war ->manifest classpath:jar1 -------jar2 war depends on jar1 and jar2 Currently, you can specify to add a manifest classpath entry. This adds an entry for each dependency that is not "Provided", because provided means "provided by the container". (CORRECT) In the above example, I can't configure maven to exclude jar1 from the war/WEB-INF/lib dir but include it in the classpath manifest. It appears to me that we need another dependency attribute to accompany scope "Provided", say <providedByManifestClasspath>true</providedByManifestClasspath> or a <providedBy>CONTAINER|MF-CP</providedBy> etc. In this solution, we wouldn't need the manifest->addClasspath plugin config. The war builder would only include the artifact in the war when the scope wasn't provided and the war archiver would know when to include the dependency in the manifest classpath. You would still require the manifest classpath prefix config. Does this make sense? Is there a way to accomplish this already?
Hide
Al Robertson added a comment -

No-one has commented on this yet.
I would like to escalate this as I believe m2 is not able to meet j2ee packaging requirements as it stands.
Could Jason/Brett comment on this? I'm happy to be proved wrong as deployment is only semi-automated for me at the moment

Show
Al Robertson added a comment - No-one has commented on this yet. I would like to escalate this as I believe m2 is not able to meet j2ee packaging requirements as it stands. Could Jason/Brett comment on this? I'm happy to be proved wrong as deployment is only semi-automated for me at the moment
Hide
Wonne Keysers added a comment -

Compile time dependencies can be excluded from the WEB-INF/lib by using the <optional>true</optional> flag. However, this currently does not work recursively.

For example: if the war has a dependency on A.jar, but A.jar itself s dependant from B.jar, putting the A-dependency optional excludes it from the war (yet it includes it in the manifest), but B.jar is still included in the WEB-INF/lib.

If the optional flag would be working recursively, I think the solution would be complete?

Show
Wonne Keysers added a comment - Compile time dependencies can be excluded from the WEB-INF/lib by using the <optional>true</optional> flag. However, this currently does not work recursively. For example: if the war has a dependency on A.jar, but A.jar itself s dependant from B.jar, putting the A-dependency optional excludes it from the war (yet it includes it in the manifest), but B.jar is still included in the WEB-INF/lib. If the optional flag would be working recursively, I think the solution would be complete?
Hide
Mike Perham added a comment -

Wonne, using <optional> or the provided scope to exclude jars from WEB-INF/lib is a horrible hack and certainly should not be endorsed officially by the plugin.

Show
Mike Perham added a comment - Wonne, using <optional> or the provided scope to exclude jars from WEB-INF/lib is a horrible hack and certainly should not be endorsed officially by the plugin.
Hide
Joe Mays added a comment -

I agree with Al; until we can support packaging a mixture of WAR dependencies using WEB-INF/lib and MANIFEST.MF, m2 does not support JEE packaging requirements.

Show
Joe Mays added a comment - I agree with Al; until we can support packaging a mixture of WAR dependencies using WEB-INF/lib and MANIFEST.MF, m2 does not support JEE packaging requirements.
Hide
M. van Leeuwen added a comment -

Is adding a new scope not the easiest way? Just configure the dependency with scope 'ear' and it will not be included as jar in the WAR, but in the EAR. The plugin should without any configuration find these scoped dependencies and add them as a classpath entry to the manifest.

Show
M. van Leeuwen added a comment - Is adding a new scope not the easiest way? Just configure the dependency with scope 'ear' and it will not be included as jar in the WAR, but in the EAR. The plugin should without any configuration find these scoped dependencies and add them as a classpath entry to the manifest.
Hide
Bryan Loofbourrow added a comment -

I agree that adding an ear scope seems like the most straightforward from a user point of view. Philosophically, it's like a variation on provided, but meaning "provided in the ear."

I also agree with those who say that supporting a mixture of in-war and in-ear jars is essential. Some jars have to be in the war. Examples: either jstl or standard tag library jars (haven't narrowed it down to discover which) must be in the war, it appears. The same appears to apply to myfaces. Perhaps a consequence of loading resources with a path instead of classpath.

Show
Bryan Loofbourrow added a comment - I agree that adding an ear scope seems like the most straightforward from a user point of view. Philosophically, it's like a variation on provided, but meaning "provided in the ear." I also agree with those who say that supporting a mixture of in-war and in-ear jars is essential. Some jars have to be in the war. Examples: either jstl or standard tag library jars (haven't narrowed it down to discover which) must be in the war, it appears. The same appears to apply to myfaces. Perhaps a consequence of loading resources with a path instead of classpath.
Hide
Stephane Nicoll added a comment -

What about using a classifier for the skeleton war?

Show
Stephane Nicoll added a comment - What about using a classifier for the skeleton war?
Hide
Cliff Resnick added a comment -

After searching, I have not found any resolution for this problem. Is there one?

In the meantime, for my own purposes I have altered the plugin to so that "optional=true" works recursively, simply by checking for existence of optional artifacts in the dependency trail of all resolved artifacts.

This finally gives me what I consider desired (at least tolerable) behavior:

scope:compile = classpath and WEB-INF/lib (though cp is not necessary, it doesn't hurt)
scope:provided = no classpath, no WEB-INF/lib
optional = transitively resolved artifacts on classpath, no WEB-INF/lib

I know this is just furthering a hack, but I'm not sure how else to do it since there seems to be an inherent containment issue where war shouldn't know about the ear. Where I work, we use what we consider a "best practice" approach where ear, war, sar, etc. projects are siblings, with a parent "server" pom project providing all container-based scope=provided dependencies. This primarily filters all container-provided compile dependencies used by core components, greatly simplifying the poms of the container-based components. I know it may be a stretch, but perhaps such a "container" parent project could be somehow formalized, at least to provided a way to formally put the ear before the war? Just a thought...

Show
Cliff Resnick added a comment - After searching, I have not found any resolution for this problem. Is there one? In the meantime, for my own purposes I have altered the plugin to so that "optional=true" works recursively, simply by checking for existence of optional artifacts in the dependency trail of all resolved artifacts. This finally gives me what I consider desired (at least tolerable) behavior: scope:compile = classpath and WEB-INF/lib (though cp is not necessary, it doesn't hurt) scope:provided = no classpath, no WEB-INF/lib optional = transitively resolved artifacts on classpath, no WEB-INF/lib I know this is just furthering a hack, but I'm not sure how else to do it since there seems to be an inherent containment issue where war shouldn't know about the ear. Where I work, we use what we consider a "best practice" approach where ear, war, sar, etc. projects are siblings, with a parent "server" pom project providing all container-based scope=provided dependencies. This primarily filters all container-provided compile dependencies used by core components, greatly simplifying the poms of the container-based components. I know it may be a stretch, but perhaps such a "container" parent project could be somehow formalized, at least to provided a way to formally put the ear before the war? Just a thought...
Hide
Jason Melnick added a comment - - edited

The all-or-nothing approach to WAR/EAR packaging isn't sufficient. Some jars will need to be packaged in the war (like struts, for example) while others (almost eveyrhting else) needs to be packaged in the EAR. The WAR's directions (speficying deps as optional) will work with a patch.

I have a fix for this and will supply a patch ASAP.

See http://jira.codehaus.org/browse/MWAR-21 and http://jira.codehaus.org/browse/MNG-3067

Show
Jason Melnick added a comment - - edited The all-or-nothing approach to WAR/EAR packaging isn't sufficient. Some jars will need to be packaged in the war (like struts, for example) while others (almost eveyrhting else) needs to be packaged in the EAR. The WAR's directions (speficying deps as optional) will work with a patch. I have a fix for this and will supply a patch ASAP. See http://jira.codehaus.org/browse/MWAR-21 and http://jira.codehaus.org/browse/MNG-3067
Hide
Jason Melnick added a comment -

After more testing the posted patch doesn't work as intended as it removes the transitive dependencies of non-optional deps. Am working on the correct fix now and will repost.

Show
Jason Melnick added a comment - After more testing the posted patch doesn't work as intended as it removes the transitive dependencies of non-optional deps. Am working on the correct fix now and will repost.
Hide
Olivier Lamy added a comment -

Do we have to add the same feature as in the jar plugin ?
With the flag http://maven.apache.org/plugins/maven-jar-plugin/jar-mojo.html#useDefaultManifestFile

Show
Olivier Lamy added a comment - Do we have to add the same feature as in the jar plugin ? With the flag http://maven.apache.org/plugins/maven-jar-plugin/jar-mojo.html#useDefaultManifestFile
Hide
Barend Garvelink added a comment -

This comment adds the words "skinny war" to this issue, because that's the name used in http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html and therefore a likely search key. (I overlooked this one yesterday)

Show
Barend Garvelink added a comment - This comment adds the words "skinny war" to this issue, because that's the name used in http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html and therefore a likely search key. (I overlooked this one yesterday)
Hide
Barend Garvelink added a comment -

This is a big issue for a lot of people, and the information on it appears to be very fragmented. I have tried to summarize all the information related to this issue on the Codehaus wiki so that a good, lasting solution can hopefully be found. Please chip in with your thoughts:

http://docs.codehaus.org/display/MAVENUSER/Solving+the+Skinny+Wars+problem

Show
Barend Garvelink added a comment - This is a big issue for a lot of people, and the information on it appears to be very fragmented. I have tried to summarize all the information related to this issue on the Codehaus wiki so that a good, lasting solution can hopefully be found. Please chip in with your thoughts: http://docs.codehaus.org/display/MAVENUSER/Solving+the+Skinny+Wars+problem
Hide
Nicolas Marcotte added a comment - - edited

Oups wrong ticket please delete the attached file

Show
Nicolas Marcotte added a comment - - edited Oups wrong ticket please delete the attached file
Hide
Dennis Lundberg added a comment -

I would like to close this issue as "Won't fix".

The proper way to solve this is in the EAR Plugin, like the proposals in MEAR-60 and MEAR-87.

Show
Dennis Lundberg added a comment - I would like to close this issue as "Won't fix". The proper way to solve this is in the EAR Plugin, like the proposals in MEAR-60 and MEAR-87.
Hide
Nicolas Marcotte added a comment -

As a maven user and in house plugins developer I wholeheartedly agree. However i would still like to see my updated test and documentations for MWAR-81 included as a stop gap measure.

If my last patch to MWAR-81 is included I can document it on the cited wiki, tell the readers to subscribe to MEAR-60 and MEAR-87 for a correct solution while using MWAR-81 while we wait while proper patch is developed.

However, I won't update the wiki if MWAR-81 is not included because if there are no test nor documentation on that functionality, it can disappear in any future release and it is a behaviour that would I dislike to see as a maven user and evangelist 1 !

  1. I may have drunk to much Koolaid but,hey!, your maven Koolaid taste so good.
Show
Nicolas Marcotte added a comment - As a maven user and in house plugins developer I wholeheartedly agree. However i would still like to see my updated test and documentations for MWAR-81 included as a stop gap measure. If my last patch to MWAR-81 is included I can document it on the cited wiki, tell the readers to subscribe to MEAR-60 and MEAR-87 for a correct solution while using MWAR-81 while we wait while proper patch is developed. However, I won't update the wiki if MWAR-81 is not included because if there are no test nor documentation on that functionality, it can disappear in any future release and it is a behaviour that would I dislike to see as a maven user and evangelist 1 !
  1. I may have drunk to much Koolaid but,hey!, your maven Koolaid taste so good.
Hide
Dennis Lundberg added a comment -

MWAR-81 will be included in the next WAR Plugin release.

Show
Dennis Lundberg added a comment - MWAR-81 will be included in the next WAR Plugin release.

People

Vote (59)
Watch (47)

Dates

  • Created:
    Updated:
    Resolved: