Maven WAR Plugin
  1. Maven WAR Plugin
  2. MWAR-9

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
          Stéphane Nicoll added a comment -

          What about using a classifier for the skeleton war?

          Show
          Stéphane 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 ! 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

            • Assignee:
              Unassigned
              Reporter:
              Mike Perham
            • Votes:
              59 Vote for this issue
              Watchers:
              47 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: