Maven Ear Plugin
  1. Maven Ear Plugin
  2. MEAR-60

Improve support for skinny war files

    Details

    • Type: Improvement Improvement
    • Status: Closed Closed
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: 2.3
    • Fix Version/s: 2.7
    • Labels:
      None
    • Environment:
      mvn 2.0.5
    • Number of attachments :
      3

      Description

      Provide a boolean configuration option for webModules to include the war's transitive dependencies.

      As described on http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html it is very common in a J2EE environment to use so called skinny wars. Here the war's WEB-INF/lib will not contain the dependent jars, but instead they are packaged inside the EAR. The war references them through its META-INF/MANIFEST.MF

      This option could be used to avoid the 'painful part' mentioned in the above web page. The war's dependencies wouldn't have to be duplicated alongside the ear's.

      I also found an old issue (MEAR-14) which has asked for the current default behavior of not including the transitive dependencies. It suggests a property to include specific dependencies of the war. As far as I can tell this has never been implemented and this is also not what I am asking for. My proposal is an all of nothing kind of option for each war module in the ear.

      On a side note, for me this is the part where removal of the old maven 1 style properties per dependency is missed the most. With them it was possible to decide for each single dependency whether to put it in WEB-INF/lib or reference it through the manifest classpath. But of course, then we didn't have the transitive dependencies

        Issue Links

          Activity

          Hide
          Heinrich Nirschl added a comment -

          I don't think that a boolean configuration option is flexible enough. There are situations where you want most of your jars in the ear, but still some of them in the war (for example, if they contain a tag library - the jsp compiler does not find the tag library if it is in the ear).

          Show
          Heinrich Nirschl added a comment - I don't think that a boolean configuration option is flexible enough. There are situations where you want most of your jars in the ear, but still some of them in the war (for example, if they contain a tag library - the jsp compiler does not find the tag library if it is in the ear).
          Hide
          Marcel Schutte added a comment -

          I agree that extra flexibility is needed. It is just that as far as I understand maven, such a change would have a major impact on mavens dependency handling. I don't think that is going to happen soon and therefore I am trying what for me is 'the next best thing'.

          Show
          Marcel Schutte added a comment - I agree that extra flexibility is needed. It is just that as far as I understand maven, such a change would have a major impact on mavens dependency handling. I don't think that is going to happen soon and therefore I am trying what for me is 'the next best thing'.
          Hide
          Stéphane Nicoll added a comment -

          There's nothing I can do at this point. We need an update on how war dependencies are handled.

          Show
          Stéphane Nicoll added a comment - There's nothing I can do at this point. We need an update on how war dependencies are handled.
          Hide
          Brian Topping added a comment -

          A new build I am working on needs the jars available to non-web resources, so a skinny war is needed. Ouch.

          It seems like state should be able to be stored in the WAR manifest that a skinny WAR is desired, and the EAR plugin looks at the manifest to see if it has that flag. If so, the POM in the WAR is parsed and the dependencies (with transitives) is included.

          Truly, the 'painful part' of this isn't getting the direct dependencies of the WAR into the ear, it's all the transitives. Suddenly, one of the best things about m2 is broken.

          I would code this up, but I haven't had much luck getting patches applied before they go stale, resulting in a lot of wasted effort. If someone made a commitment to apply this, I would code it with the test cases.

          Show
          Brian Topping added a comment - A new build I am working on needs the jars available to non-web resources, so a skinny war is needed. Ouch. It seems like state should be able to be stored in the WAR manifest that a skinny WAR is desired, and the EAR plugin looks at the manifest to see if it has that flag. If so, the POM in the WAR is parsed and the dependencies (with transitives) is included. Truly, the 'painful part' of this isn't getting the direct dependencies of the WAR into the ear, it's all the transitives. Suddenly, one of the best things about m2 is broken. I would code this up, but I haven't had much luck getting patches applied before they go stale, resulting in a lot of wasted effort. If someone made a commitment to apply this, I would code it with the test cases.
          Hide
          Barend Garvelink added a comment -

          Created a link between this issue and MEAR-75 (module manifest Class-Paths) because some application servers (e.g. WAS 5.1) require a correct manifest Class-Path in a skinny WAR to make it work.

          Show
          Barend Garvelink added a comment - Created a link between this issue and MEAR-75 (module manifest Class-Paths) because some application servers (e.g. WAS 5.1) require a correct manifest Class-Path in a skinny WAR to make it work.
          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
          Jeroen Ruijgers added a comment -

          the attached patch solves the 'skinny war' problem.

          the patch deletes all .jar files included in the modules and rewrites all MANIFES.MF/Class-Path entries for JavaE modules.

          It absolutely needs some rewriting and optimalization, but in the basics this is a good working solution

          Show
          Jeroen Ruijgers added a comment - the attached patch solves the 'skinny war' problem. the patch deletes all .jar files included in the modules and rewrites all MANIFES.MF/Class-Path entries for JavaE modules. It absolutely needs some rewriting and optimalization, but in the basics this is a good working solution
          Hide
          Stephen Coy added a comment -

          Actually we need to be a little careful of the "all" approach because spec wise, the container will only look for taglibs in jars within the WEB-INF/lib directory of the WAR.

          Show
          Stephen Coy added a comment - Actually we need to be a little careful of the "all" approach because spec wise, the container will only look for taglibs in jars within the WEB-INF/lib directory of the WAR.
          Hide
          Jeroen Ruijgers added a comment - - edited

          only the dependencies which are dependencies of both the ear en war will be deleted. So if you make sure your dependency with taglibs are listed as a dependency for the war, it will not be deleted.

          the only nasty thing in this solution is the fact that a module must be unpacked, modified and repacked. the standard zip files don't support changing or deleting entries.

          Show
          Jeroen Ruijgers added a comment - - edited only the dependencies which are dependencies of both the ear en war will be deleted. So if you make sure your dependency with taglibs are listed as a dependency for the war, it will not be deleted. the only nasty thing in this solution is the fact that a module must be unpacked, modified and repacked. the standard zip files don't support changing or deleting entries.
          Hide
          Eric Pabst added a comment -

          The patch has a lot of reformatting in it. I fixed the formatting, rebased it onto the latest trunk, and pushed it to:

          https://github.com/epabst/maven-plugins/tree/MEAR-60

          I want to do something related, and having this to go from was helpful.

          Show
          Eric Pabst added a comment - The patch has a lot of reformatting in it. I fixed the formatting, rebased it onto the latest trunk, and pushed it to: https://github.com/epabst/maven-plugins/tree/MEAR-60 I want to do something related, and having this to go from was helpful.
          Hide
          Dennis Lundberg added a comment -

          Eric,

          Would it be possible for you to extract your github commit as a patch-file, so that I can apply it to Maven's svn repo? I'm very interested in getting this functionality into a released version of the EAR Plugin. We do need some tests and documentation before we are release ready, but the patch looks good to me on the first read through.

          Show
          Dennis Lundberg added a comment - Eric, Would it be possible for you to extract your github commit as a patch-file, so that I can apply it to Maven's svn repo? I'm very interested in getting this functionality into a released version of the EAR Plugin. We do need some tests and documentation before we are release ready, but the patch looks good to me on the first read through.
          Hide
          Dennis Lundberg added a comment -

          Here's a status report.

          I've managed to extract a patch from Eric's Github repo. It's applied locally and I have modified it so that all the current integration tests pass. There were two cases where the current ITs failed. A new integration test for skinny wars have been added.

          This is a change that will affect many projects, and I feel that we should have a parameter in the EarMojo to enable this new functionality. It should be disabled by default, to preserve the current behavior. I suggest a boolean parameter called "skinnyWars".

          What do you think?

          Show
          Dennis Lundberg added a comment - Here's a status report. I've managed to extract a patch from Eric's Github repo. It's applied locally and I have modified it so that all the current integration tests pass. There were two cases where the current ITs failed. A new integration test for skinny wars have been added. This is a change that will affect many projects, and I feel that we should have a parameter in the EarMojo to enable this new functionality. It should be disabled by default, to preserve the current behavior. I suggest a boolean parameter called "skinnyWars". What do you think?
          Hide
          Jeroen Ruijgers added a comment -

          Thanks! A long awaited change. I think the name is good and descriptive.

          Show
          Jeroen Ruijgers added a comment - Thanks! A long awaited change. I think the name is good and descriptive.
          Hide
          Dennis Lundberg added a comment -

          The patch from Jeroen and Eric was applied with modifications and the addition of an IT in r1210910.

          In r1210930 I added the paramter to enable skinnyWars together with another IT.

          I'll also add some examples in the documentation showing how it is used and what it does in more detail.

          A new 2.7-SNAPSHOT has been deployed. It would be great if we could get some reports on how this works for everyone who has voted on this issue.

          Show
          Dennis Lundberg added a comment - The patch from Jeroen and Eric was applied with modifications and the addition of an IT in r1210910 . In r1210930 I added the paramter to enable skinnyWars together with another IT. I'll also add some examples in the documentation showing how it is used and what it does in more detail. A new 2.7-SNAPSHOT has been deployed. It would be great if we could get some reports on how this works for everyone who has voted on this issue.
          Hide
          Andreas Thaler added a comment -

          For me it works really fine in general.
          I have a problem in case the war contains artifacts having unique timestamp based version numbers.
          It seems that the war plugin uses the Artifact.getVersion() method for resolving of artifact files while the ear plugin uses the Artifact.getBaseVersion() method. With this the artifacts in my war are not detected as already contained in ear and will be not removed from war.
          I found a workaround by configuring a custom fileNameMapping for the ear plugin using the getVersion() method for artifact file resolving. With this everything works perfect.

          Show
          Andreas Thaler added a comment - For me it works really fine in general. I have a problem in case the war contains artifacts having unique timestamp based version numbers. It seems that the war plugin uses the Artifact.getVersion() method for resolving of artifact files while the ear plugin uses the Artifact.getBaseVersion() method. With this the artifacts in my war are not detected as already contained in ear and will be not removed from war. I found a workaround by configuring a custom fileNameMapping for the ear plugin using the getVersion() method for artifact file resolving. With this everything works perfect.
          Hide
          Dennis Lundberg added a comment -

          Andreas,

          Thanks for your feedback! Would you mind sharing your configuration with us. I'd like to add it to the documentation, in case others face the same issue.

          Show
          Dennis Lundberg added a comment - Andreas, Thanks for your feedback! Would you mind sharing your configuration with us. I'd like to add it to the documentation, in case others face the same issue.
          Hide
          Dennis Lundberg added a comment -

          Documentation was added in r1212271.

          Show
          Dennis Lundberg added a comment - Documentation was added in r1212271 .
          Hide
          Andreas Thaler added a comment -

          Hi Dennis,

          I would prefer to see the problem solved rather than documented as the workaround involves custom code. Without the workaround the skinnyWar issue is not solved from my perspective..

          However here my solution with which it is working fine for me:
          I created a jar containing a single java file implementing the FileNameMapping interface. The implementation uses Artifact.getVersion() instead of Artifact.getBaseVersion() used in AbstractFileNameMapping. So the libs placed to the ear will have the same file name as in the war and duplicates will be detected. I attached the jar to this issue.
          At the plugin configuration the fileNameMapping property must be configured to the custom file in the new jar. Furthermore the dependency to the jar must be configured at the plugin.

          <plugin>
          	<groupId>org.apache.maven.plugins</groupId>
          	<artifactId>maven-ear-plugin</artifactId>
          	<version>2.7-SNAPSHOT</version>
          	<configuration>
          		<!-- Custom FileNameMapping provided in additional jar to use unique 
          			timestamp version for jars, otherwise duplicated jars will not be recognized -->
          		<fileNameMapping>de.hybris.maven.VersionFileNameMapping</fileNameMapping>
          		<skinnyWars>true</skinnyWars>
          		<defaultLibBundleDir>lib</defaultLibBundleDir>
          	</configuration>
          	<dependencies>
          		<dependency>
          			<groupId>de.hybris.maven</groupId>
          			<artifactId>maven-ear-plugin-addon</artifactId>
          			<version>1.0-SNAPSHOT</version>
          		</dependency>
          	</dependencies>
          </plugin>
          

          Thanks for bringing this whole story to an end,
          Andreas

          Show
          Andreas Thaler added a comment - Hi Dennis, I would prefer to see the problem solved rather than documented as the workaround involves custom code. Without the workaround the skinnyWar issue is not solved from my perspective.. However here my solution with which it is working fine for me: I created a jar containing a single java file implementing the FileNameMapping interface. The implementation uses Artifact.getVersion() instead of Artifact.getBaseVersion() used in AbstractFileNameMapping. So the libs placed to the ear will have the same file name as in the war and duplicates will be detected. I attached the jar to this issue. At the plugin configuration the fileNameMapping property must be configured to the custom file in the new jar. Furthermore the dependency to the jar must be configured at the plugin. <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ear-plugin</artifactId> <version>2.7-SNAPSHOT</version> <configuration> <!-- Custom FileNameMapping provided in additional jar to use unique timestamp version for jars, otherwise duplicated jars will not be recognized --> <fileNameMapping>de.hybris.maven.VersionFileNameMapping</fileNameMapping> <skinnyWars> true </skinnyWars> <defaultLibBundleDir>lib</defaultLibBundleDir> </configuration> <dependencies> <dependency> <groupId>de.hybris.maven</groupId> <artifactId>maven-ear-plugin-addon</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </plugin> Thanks for bringing this whole story to an end, Andreas
          Hide
          Andreas Thaler added a comment -

          Workaround jar for unique timestamp versioning problem

          Show
          Andreas Thaler added a comment - Workaround jar for unique timestamp versioning problem
          Hide
          Dennis Lundberg added a comment -

          Thanks a lot Andreas.

          I'm still playing around with the code you sent. Trying to wrap my head around what, when and how things are happening the way they do.

          My current path forward is to include a new FileNameMapping implementation in the plugin, based on your code. I just need to understand the mechanics, to be able to find suitable names.

          Do you have any data on your environment when skinny wars does and does not work? Maven version, OS and WAR plugin version etc.

          Show
          Dennis Lundberg added a comment - Thanks a lot Andreas. I'm still playing around with the code you sent. Trying to wrap my head around what, when and how things are happening the way they do. My current path forward is to include a new FileNameMapping implementation in the plugin, based on your code. I just need to understand the mechanics, to be able to find suitable names. Do you have any data on your environment when skinny wars does and does not work? Maven version, OS and WAR plugin version etc.
          Hide
          Andreas Thaler added a comment -

          Hi Dennis,

          with my setup it is failing nearly always. It looks like this:
          Project myJar which contains classes needed by all my webapps and is of type jar.
          Project myWar1 using myJar and is of type war
          Project myWar2 using myJar and is of type war
          Project myEar of type ear using ear plugin for ear creation

          My workflow looks like this: Call "mvn install" on myJar. As a result the jar will be installed to the local repo. As the project has a snapshot version the timestamp version will be used as stated in docu: http://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Available_Variables (Unfortunately I'm not able to reproduce it stable that a jar will be created in repo using timestamp )
          Afterwards I'm calling mvn install on the war projects, as the result the wars get created having the timestamp based jars in lib folder.
          When you call mvn install on the ear project the jars will be placed also to the ear but using non-timestamp version and so they will not get removed from war.
          Key point here to reproduce it is to get a timestamp version of your jar project installed to the local repo.

          I'm using Maven 3.0.3 and java 1.7.01 on windows 7. War-plugin 2.1.1

          I hope you can reproduce it, don't hesitate to ask further.

          Thanks in advance,
          Andreas

          Show
          Andreas Thaler added a comment - Hi Dennis, with my setup it is failing nearly always. It looks like this: Project myJar which contains classes needed by all my webapps and is of type jar. Project myWar1 using myJar and is of type war Project myWar2 using myJar and is of type war Project myEar of type ear using ear plugin for ear creation My workflow looks like this: Call "mvn install" on myJar. As a result the jar will be installed to the local repo. As the project has a snapshot version the timestamp version will be used as stated in docu: http://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Available_Variables (Unfortunately I'm not able to reproduce it stable that a jar will be created in repo using timestamp ) Afterwards I'm calling mvn install on the war projects, as the result the wars get created having the timestamp based jars in lib folder. When you call mvn install on the ear project the jars will be placed also to the ear but using non-timestamp version and so they will not get removed from war. Key point here to reproduce it is to get a timestamp version of your jar project installed to the local repo. I'm using Maven 3.0.3 and java 1.7.01 on windows 7. War-plugin 2.1.1 I hope you can reproduce it, don't hesitate to ask further. Thanks in advance, Andreas
          Hide
          Dennis Lundberg added a comment -

          Hi Andreas,

          I've done some more testing and have come to the following conclusions:

          • When you "mvn install" something into the local repo it will always be a -SNAPSHOT version
          • When you "mvn deploy" something it will depend on the settings of the repo and which version of Maven you use. Maven 3 will always deploy a timestamped version in the remote repo
          • I haven't been able to successfully remove a timestamped version from a WAR using your custom fileNameMapper. When I run my test project version and baseVersion are always the same

          It seems to me that it is the WAR plugin that is at fault here. It should IMO not include timestamped versions of JARs inside a WAR.

          Show
          Dennis Lundberg added a comment - Hi Andreas, I've done some more testing and have come to the following conclusions: When you "mvn install" something into the local repo it will always be a -SNAPSHOT version When you "mvn deploy" something it will depend on the settings of the repo and which version of Maven you use. Maven 3 will always deploy a timestamped version in the remote repo I haven't been able to successfully remove a timestamped version from a WAR using your custom fileNameMapper. When I run my test project version and baseVersion are always the same It seems to me that it is the WAR plugin that is at fault here. It should IMO not include timestamped versions of JARs inside a WAR.
          Hide
          Dennis Lundberg added a comment -

          I'm closing this issue as fixed now.

          Andreas, if you manage to put together a reproducible example project for the versioning issue, please open a new issue for that. If we get a release out we can get more people to test this in the wild, and perhaps they can help us zoom in on the that issue.

          Show
          Dennis Lundberg added a comment - I'm closing this issue as fixed now. Andreas, if you manage to put together a reproducible example project for the versioning issue, please open a new issue for that. If we get a release out we can get more people to test this in the wild, and perhaps they can help us zoom in on the that issue.
          Hide
          Andreas Thaler added a comment -

          Hi Dennis,

          Purpose of my fileNameMapper was not to remove the timestamped version from war, instead it configured the ear to use timestamped versions for the shared libs.
          Nevertheless I changed my code now by configuring the war plugin to use non-timestamped versions and now it works fine. I always avoided this approach as I have many war projects to configure contra one ear project, but it is ok.

          thanks for your support, am looking forward to the new release

          Show
          Andreas Thaler added a comment - Hi Dennis, Purpose of my fileNameMapper was not to remove the timestamped version from war, instead it configured the ear to use timestamped versions for the shared libs. Nevertheless I changed my code now by configuring the war plugin to use non-timestamped versions and now it works fine. I always avoided this approach as I have many war projects to configure contra one ear project, but it is ok. thanks for your support, am looking forward to the new release
          Hide
          Connor Barry added a comment -

          Hi Andreas, I'm a little new to Maven internals but experiencing this exact problem as well. How did you configure your war plugin to use the non-timestamped version of the jar dependencies? I feel like that is a little cleaner than keeping the timestamp versions around in the EAR's APP-INF/lib folder.

          Show
          Connor Barry added a comment - Hi Andreas, I'm a little new to Maven internals but experiencing this exact problem as well. How did you configure your war plugin to use the non-timestamped version of the jar dependencies? I feel like that is a little cleaner than keeping the timestamp versions around in the EAR's APP-INF/lib folder.
          Hide
          Andreas Thaler added a comment -

          I configured the outputFileNameMapping for the war-plugin like that:

          <plugin>
          	<groupId>org.apache.maven.plugins</groupId>
          	<artifactId>maven-war-plugin</artifactId>
          	<version>2.1.1</version>
          	<configuration>
          		<!-- use baseVersion instead of unique timestamp version to support skinny WARS -->
          		<outputFileNameMapping>@{artifactId}@-@{baseVersion}@.@{extension}@</outputFileNameMapping>
          	</configuration>
          </plugin>
          
          Show
          Andreas Thaler added a comment - I configured the outputFileNameMapping for the war-plugin like that: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.1.1</version> <configuration> <!-- use baseVersion instead of unique timestamp version to support skinny WARS --> <outputFileNameMapping>@{artifactId}@-@{baseVersion}@.@{extension}@</outputFileNameMapping> </configuration> </plugin>

            People

            • Assignee:
              Dennis Lundberg
              Reporter:
              Marcel Schutte
            • Votes:
              50 Vote for this issue
              Watchers:
              40 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: