Index: src/main/java/org/apache/maven/plugin/war/AbstractWarMojo.java
===================================================================
--- src/main/java/org/apache/maven/plugin/war/AbstractWarMojo.java (revision 332182)
+++ src/main/java/org/apache/maven/plugin/war/AbstractWarMojo.java (working copy)
@@ -20,8 +20,13 @@
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.archiver.ArchiverException;
+import org.codehaus.plexus.archiver.UnArchiver;
+import org.codehaus.plexus.archiver.manager.ArchiverManager;
+import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.StringUtils;
import java.io.File;
import java.io.IOException;
@@ -74,6 +79,23 @@
* @parameter expression="${maven.war.webxml}"
*/
private String webXml;
+
+ /**
+ * Directory to unpack dependent WARs into if needed
+ *
+ * @parameter expression="${project.build.directory}/war/work"
+ * @required
+ */
+ private File workDirectory;
+
+ /**
+ * To look up Archiver/UnArchiver implementations
+ *
+ * @parameter expression="${component.org.codehaus.plexus.archiver.manager.ArchiverManager}"
+ * @required
+ */
+ protected ArchiverManager archiverManager;
+
public static final String WEB_INF = "WEB-INF";
@@ -91,6 +113,23 @@
* @parameter alias="excludes"
*/
private String warSourceExcludes;
+
+ /**
+ * The comma separated list of tokens to include when doing
+ * a war overlay.
+ * Default is '**'
+ *
+ * @parameter
+ */
+ private String dependentWarIncludes = "**";
+
+ /**
+ * The comma separated list of tokens to exclude when doing
+ * a way overlay.
+ *
+ * @parameter
+ */
+ private String dependentWarExcludes;
private static final String[] EMPTY_STRING_ARRAY = {};
@@ -155,8 +194,8 @@
*/
protected String[] getExcludes()
{
- List excludeList = new ArrayList( FileUtils.getDefaultExcludesAsList() );
- if ( warSourceExcludes != null && !"".equals( warSourceExcludes ) )
+ List excludeList = new ArrayList();
+ if ( StringUtils.isNotEmpty(warSourceExcludes) )
{
excludeList.add( warSourceExcludes );
}
@@ -180,7 +219,33 @@
{
return new String[]{warSourceIncludes};
}
+
+ /**
+ * Returns a string array of the excludes to be used
+ * when adding dependent wars as an overlay onto this war.
+ *
+ * @return an array of tokens to exclude
+ */
+ protected String[] getDependentWarExcludes() {
+ List excludeList = new ArrayList();
+ if ( StringUtils.isNotEmpty(dependentWarExcludes) )
+ {
+ excludeList.add( dependentWarExcludes );
+ }
+ return (String[]) excludeList.toArray( EMPTY_STRING_ARRAY );
+ }
+
+ /**
+ * Returns a string array of the includes to be used
+ * when adding dependent wars as an overlay onto this war.
+ *
+ * @return an array of tokens to include
+ */
+ protected String[] getDependentWarIncludes() {
+ return new String[] { dependentWarIncludes };
+ }
+
public void buildExplodedWebapp( File webappDirectory )
throws MojoExecutionException
{
@@ -253,7 +318,7 @@
* @throws java.io.IOException if an error occured while building the webapp
*/
public void buildWebapp( MavenProject project, File webappDirectory )
- throws IOException
+ throws MojoExecutionException, IOException
{
getLog().info( "Assembling webapp " + project.getArtifactId() + " in " + webappDirectory );
@@ -269,6 +334,8 @@
}
Set artifacts = project.getArtifacts();
+
+ List dependentWarDirectories = new ArrayList();
for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
{
@@ -287,15 +354,147 @@
{
FileUtils.copyFileToDirectory( artifact.getFile(), libDirectory );
}
+ else if ( "war".equals( type ) )
+ {
+ dependentWarDirectories.add( unpackWarToTempDirectory( artifact ) );
+ }
else
{
getLog().debug( "Skipping artifact of type " + type + " for WEB-INF/lib" );
}
}
}
+
+ if ( dependentWarDirectories.size() > 0 )
+ {
+ getLog().info( "Overlaying " + dependentWarDirectories.size() + " war(s)." );
+
+ // overlay dependent wars
+ for ( Iterator iter = dependentWarDirectories.iterator(); iter.hasNext(); )
+ {
+ copyDependentWarContents( (File) iter.next(), webappDirectory );
+ }
+ }
}
+
+ /**
+ * Unpacks war artifacts into a temporary directory inside workDirectory
+ * named with the name of the war.
+ *
+ * @param artifact War artifact to unpack.
+ * @return Directory containing the unpacked war.
+ * @throws MojoExecutionException
+ */
+ private File unpackWarToTempDirectory( Artifact artifact )
+ throws MojoExecutionException
+ {
+ String name = artifact.getFile().getName();
+ File tempLocation = new File( workDirectory, name.substring( 0, name.length() - 4 ) );
+ boolean process = false;
+ if ( !tempLocation.exists() )
+ {
+ tempLocation.mkdirs();
+ process = true;
+ }
+ else if ( artifact.getFile().lastModified() > tempLocation.lastModified() )
+ {
+ process = true;
+ }
+
+ if ( process )
+ {
+ File file = artifact.getFile();
+ try
+ {
+ unpack( file, tempLocation );
+ }
+ catch ( NoSuchArchiverException e )
+ {
+ this.getLog().info( "Skip unpacking dependency file with unknown extension: " + file.getPath() );
+ }
+ }
+
+ return tempLocation;
+ }
+
/**
+ * Unpacks the archive file.
+ *
+ * @param file File to be unpacked.
+ * @param location Location where to put the unpacked files.
+ */
+ private void unpack( File file, File location )
+ throws MojoExecutionException, NoSuchArchiverException
+ {
+ String archiveExt = FileUtils.getExtension( file.getAbsolutePath() ).toLowerCase();
+
+ try
+ {
+ UnArchiver unArchiver;
+ unArchiver = this.archiverManager.getUnArchiver( archiveExt );
+ unArchiver.setSourceFile( file );
+ unArchiver.setDestDirectory( location );
+ unArchiver.extract();
+ }
+ catch ( IOException e )
+ {
+ throw new MojoExecutionException( "Error unpacking file: " + file + "to: " + location, e );
+ }
+ catch ( ArchiverException e )
+ {
+ throw new MojoExecutionException( "Error unpacking file: " + file + "to: " + location, e );
+ }
+ }
+
+ /**
+ * Recursively copies contents of srcDir into targetDir.
+ * This will not overwrite any existing files.
+ *
+ * @param srcDir Directory containing unpacked dependent war contents
+ * @param targetDir Directory to overlay srcDir into
+ */
+ private void copyDependentWarContents( File srcDir, File targetDir )
+ throws IOException, MojoExecutionException
+ {
+ DirectoryScanner scanner = new DirectoryScanner();
+ scanner.setBasedir( srcDir );
+ scanner.setExcludes( getDependentWarExcludes() );
+ scanner.addDefaultExcludes();
+
+ scanner.setIncludes( getDependentWarIncludes() );
+
+ scanner.scan();
+
+ String[] dirs = scanner.getIncludedDirectories();
+ for ( int j = 0; j < dirs.length; j++ )
+ {
+ new File( targetDir, dirs[j] ).mkdirs();
+ }
+
+ String[] files = scanner.getIncludedFiles();
+
+ for ( int j = 0; j < files.length; j++ )
+ {
+ File targetFile = new File( targetDir, files[j] );
+
+ // Do not overwrite existing files.
+ if (!targetFile.exists())
+ {
+ try
+ {
+ targetFile.getParentFile().mkdirs();
+ FileUtils.copyFile( new File( srcDir, files[j] ), targetFile );
+ }
+ catch ( IOException e )
+ {
+ throw new MojoExecutionException( "Error copying file '" + files[j] + "' to '" + targetFile + "'", e );
+ }
+ }
+ }
+ }
+
+ /**
* Returns a list of filenames that should be copied
* over to the destination directory.
*