Creating branch for the mappers feature so I can switch to a new machine, and also in case it takes me awhile to get these tests back up and running.


git-svn-id: https://svn.apache.org/repos/asf/maven/plugins/branches/MASSEMBLY-45@421628 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 60a6474..419c940 100755
--- a/pom.xml
+++ b/pom.xml
@@ -141,5 +141,11 @@
       <version>1.0-beta-1</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <version>1.2_Java1.3</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
diff --git a/src/main/java/org/apache/maven/plugin/assembly/AbstractAssemblyMojo.java b/src/main/java/org/apache/maven/plugin/assembly/AbstractAssemblyMojo.java
index 8c9d336..2da5946 100644
--- a/src/main/java/org/apache/maven/plugin/assembly/AbstractAssemblyMojo.java
+++ b/src/main/java/org/apache/maven/plugin/assembly/AbstractAssemblyMojo.java
@@ -16,58 +16,6 @@
  * limitations under the License.
  */
 
-import org.apache.maven.archiver.MavenArchiveConfiguration;
-import org.apache.maven.archiver.MavenArchiver;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.DependencyResolutionRequiredException;
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
-import org.apache.maven.model.Build;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.assembly.filter.AssemblyExcludesArtifactFilter;
-import org.apache.maven.plugin.assembly.filter.AssemblyIncludesArtifactFilter;
-import org.apache.maven.plugin.assembly.filter.AssemblyScopeArtifactFilter;
-import org.apache.maven.plugin.assembly.interpolation.AssemblyInterpolationException;
-import org.apache.maven.plugin.assembly.interpolation.AssemblyInterpolator;
-import org.apache.maven.plugin.assembly.interpolation.ReflectionProperties;
-import org.apache.maven.plugin.assembly.repository.RepositoryAssembler;
-import org.apache.maven.plugin.assembly.repository.RepositoryAssemblyException;
-import org.apache.maven.plugin.assembly.utils.FilterUtils;
-import org.apache.maven.plugin.assembly.utils.ProjectUtils;
-import org.apache.maven.plugin.assembly.utils.PropertyUtils;
-import org.apache.maven.plugins.assembly.model.Assembly;
-import org.apache.maven.plugins.assembly.model.Component;
-import org.apache.maven.plugins.assembly.model.DependencySet;
-import org.apache.maven.plugins.assembly.model.FileItem;
-import org.apache.maven.plugins.assembly.model.FileSet;
-import org.apache.maven.plugins.assembly.model.ModuleBinaries;
-import org.apache.maven.plugins.assembly.model.ModuleSet;
-import org.apache.maven.plugins.assembly.model.ModuleSources;
-import org.apache.maven.plugins.assembly.model.Repository;
-import org.apache.maven.plugins.assembly.model.io.xpp3.AssemblyXpp3Reader;
-import org.apache.maven.plugins.assembly.model.io.xpp3.ComponentXpp3Reader;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.project.MavenProjectHelper;
-import org.apache.maven.shared.model.fileset.util.FileSetManager;
-import org.apache.maven.wagon.PathUtils;
-import org.codehaus.plexus.archiver.Archiver;
-import org.codehaus.plexus.archiver.ArchiverException;
-import org.codehaus.plexus.archiver.jar.JarArchiver;
-import org.codehaus.plexus.archiver.jar.Manifest;
-import org.codehaus.plexus.archiver.jar.ManifestException;
-import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
-import org.codehaus.plexus.archiver.tar.TarArchiver;
-import org.codehaus.plexus.archiver.tar.TarLongFileMode;
-import org.codehaus.plexus.archiver.war.WarArchiver;
-import org.codehaus.plexus.util.DirectoryScanner;
-import org.codehaus.plexus.util.FileUtils;
-import org.codehaus.plexus.util.IOUtil;
-import org.codehaus.plexus.util.InterpolationFilterReader;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
@@ -91,13 +39,68 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.maven.archiver.MavenArchiveConfiguration;
+import org.apache.maven.archiver.MavenArchiver;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DependencyResolutionRequiredException;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
+import org.apache.maven.model.Build;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.assembly.filter.AssemblyExcludesArtifactFilter;
+import org.apache.maven.plugin.assembly.filter.AssemblyIncludesArtifactFilter;
+import org.apache.maven.plugin.assembly.filter.AssemblyScopeArtifactFilter;
+import org.apache.maven.plugin.assembly.interpolation.AssemblyInterpolationException;
+import org.apache.maven.plugin.assembly.interpolation.AssemblyInterpolator;
+import org.apache.maven.plugin.assembly.interpolation.ReflectionProperties;
+import org.apache.maven.plugin.assembly.mappers.FileNameMapper;
+import org.apache.maven.plugin.assembly.mappers.MapperUtil;
+import org.apache.maven.plugin.assembly.repository.RepositoryAssembler;
+import org.apache.maven.plugin.assembly.repository.RepositoryAssemblyException;
+import org.apache.maven.plugin.assembly.utils.FilterUtils;
+import org.apache.maven.plugin.assembly.utils.ProjectUtils;
+import org.apache.maven.plugin.assembly.utils.PropertyUtils;
+import org.apache.maven.plugins.assembly.model.Assembly;
+import org.apache.maven.plugins.assembly.model.Component;
+import org.apache.maven.plugins.assembly.model.DependencySet;
+import org.apache.maven.plugins.assembly.model.FileItem;
+import org.apache.maven.plugins.assembly.model.FileSet;
+import org.apache.maven.plugins.assembly.model.ModuleBinaries;
+import org.apache.maven.plugins.assembly.model.ModuleSet;
+import org.apache.maven.plugins.assembly.model.ModuleSources;
+import org.apache.maven.plugins.assembly.model.Repository;
+import org.apache.maven.plugins.assembly.model.Unpack;
+import org.apache.maven.plugins.assembly.model.io.xpp3.AssemblyXpp3Reader;
+import org.apache.maven.plugins.assembly.model.io.xpp3.ComponentXpp3Reader;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+import org.apache.maven.shared.model.fileset.util.FileSetManager;
+import org.apache.maven.wagon.PathUtils;
+import org.codehaus.plexus.archiver.Archiver;
+import org.codehaus.plexus.archiver.ArchiverException;
+import org.codehaus.plexus.archiver.jar.JarArchiver;
+import org.codehaus.plexus.archiver.jar.Manifest;
+import org.codehaus.plexus.archiver.jar.ManifestException;
+import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
+import org.codehaus.plexus.archiver.tar.TarArchiver;
+import org.codehaus.plexus.archiver.tar.TarLongFileMode;
+import org.codehaus.plexus.archiver.war.WarArchiver;
+import org.codehaus.plexus.util.DirectoryScanner;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.InterpolationFilterReader;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
 /**
  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
  * @version $Id$
  */
 public abstract class AbstractAssemblyMojo
-    extends AbstractUnpackingMojo
+extends AbstractUnpackingMojo
 {
     /**
      * A list of descriptor files to generate from.
@@ -222,6 +225,16 @@
      */
     private RepositoryAssembler repositoryAssembler;
 
+    /**
+     * Set to true to skip creating the zip/tar.
+     * The temporary directory and working directory which contain the files to be assembled will remain intact.
+     * This is an optional parameter.
+     *
+     * @parameter default-value="false"
+     */
+    private boolean intermediaryAssembly;
+
+
     private static final String LS = System.getProperty( "line.separator" );
 
     /**
@@ -231,7 +244,7 @@
      *
      */
     public void execute()
-        throws MojoExecutionException, MojoFailureException
+    throws MojoExecutionException, MojoFailureException
     {
         List assemblies = readAssemblies();
 
@@ -246,7 +259,7 @@
     }
 
     private void createAssembly( Assembly assembly )
-        throws MojoExecutionException, MojoFailureException
+    throws MojoExecutionException, MojoFailureException
     {
         String fullName = getDistributionName( assembly );
 
@@ -262,6 +275,11 @@
                 Archiver archiver = createArchiver( format );
 
                 destFile = createArchive( archiver, assembly, filename );
+
+                if ( intermediaryAssembly )
+                {
+                    return;
+                }
             }
             catch ( NoSuchArchiverException e )
             {
@@ -319,7 +337,7 @@
     }
 
     protected File createArchive( Archiver archiver, Assembly assembly, String filename )
-        throws MojoExecutionException, MojoFailureException, IOException, ArchiverException, RepositoryAssemblyException
+    throws MojoExecutionException, MojoFailureException, IOException, ArchiverException, RepositoryAssemblyException
     {
         processRepositories( archiver, assembly.getRepositories(), assembly.isIncludeBaseDirectory() );
         processDependencySets( archiver, assembly.getDependencySets(), assembly.isIncludeBaseDirectory() );
@@ -330,6 +348,10 @@
         componentsXmlFilter.addToArchive( archiver );
 
         File destFile = new File( outputDirectory, filename );
+        if ( intermediaryAssembly )
+        {
+            return destFile;
+        }
 
         if ( archiver instanceof JarArchiver )
         {
@@ -389,7 +411,7 @@
     }
 
     private void processRepositories( Archiver archiver, List modulesList, boolean includeBaseDirectory )
-        throws RepositoryAssemblyException, MojoExecutionException
+    throws RepositoryAssemblyException, MojoExecutionException
     {
         for ( Iterator i = modulesList.iterator(); i.hasNext(); )
         {
@@ -423,7 +445,7 @@
     }
 
     private void processModules( Archiver archiver, List moduleSets, boolean includeBaseDirectory )
-        throws MojoFailureException, MojoExecutionException
+    throws MojoFailureException, MojoExecutionException
     {
         for ( Iterator i = moduleSets.iterator(); i.hasNext(); )
         {
@@ -470,13 +492,14 @@
                     excludesList.add( PathUtils.toRelative( moduleProject.getBasedir(),
                                                             moduleProject.getBuild().getDirectory() ) + "/**" );
                     excludesList.add( PathUtils.toRelative( moduleProject.getBasedir(),
-                                                            moduleProject.getBuild().getOutputDirectory() ) + "/**" );
+                                                            moduleProject.getBuild().getOutputDirectory() ) +
+                                      "/**" );
                     excludesList.add( PathUtils.toRelative( moduleProject.getBasedir(),
                                                             moduleProject.getBuild().getTestOutputDirectory() ) +
-                        "/**" );
+                                      "/**" );
                     excludesList.add( PathUtils.toRelative( moduleProject.getBasedir(),
                                                             moduleProject.getReporting().getOutputDirectory() ) +
-                        "/**" );
+                                      "/**" );
                     moduleFileSet.setExcludes( excludesList );
 
                     moduleFileSets.add( moduleFileSet );
@@ -491,7 +514,7 @@
                     if ( moduleArtifact.getFile() == null )
                     {
                         throw new MojoExecutionException( "Included module: " + moduleProject.getId() +
-                            " does not have an artifact with a file. Please ensure the package phase is run before the assembly is generated." );
+                                                          " does not have an artifact with a file. Please ensure the package phase is run before the assembly is generated." );
                     }
 
                     String output = binaries.getOutputDirectory();
@@ -502,8 +525,8 @@
                     archiver.setDefaultFileMode( Integer.parseInt( binaries.getFileMode(), 8 ) );
 
                     getLog().debug( "ModuleSet[" + output + "]" + " dir perms: " +
-                        Integer.toString( archiver.getDefaultDirectoryMode(), 8 ) + " file perms: " +
-                        Integer.toString( archiver.getDefaultFileMode(), 8 ) );
+                                    Integer.toString( archiver.getDefaultDirectoryMode(), 8 ) + " file perms: " +
+                                    Integer.toString( archiver.getDefaultFileMode(), 8 ) );
 
                     Set binaryDependencies = moduleProject.getArtifacts();
 
@@ -512,7 +535,8 @@
 
                     FilterUtils.filterArtifacts( binaryDependencies, includes, excludes, true, Collections.EMPTY_LIST );
 
-                    if ( binaries.isUnpack() )
+                    Unpack unpack = binaries.getUnpack();
+                    if ( unpack != null )
                     {
                         // TODO: something like zipfileset in plexus-archiver
                         //                        archiver.addJar(  )
@@ -538,8 +562,7 @@
 
                                 if ( binaries.isIncludeDependencies() )
                                 {
-                                    for ( Iterator dependencyIterator = binaryDependencies.iterator();
-                                          dependencyIterator.hasNext(); )
+                                    for ( Iterator dependencyIterator = binaryDependencies.iterator(); dependencyIterator.hasNext(); )
                                     {
                                         Artifact dependencyArtifact = (Artifact) dependencyIterator.next();
 
@@ -549,7 +572,8 @@
                             }
                             catch ( NoSuchArchiverException e )
                             {
-                                throw new MojoExecutionException( "Unable to obtain unarchiver: " + e.getMessage(), e );
+                                throw new MojoExecutionException( "Unable to obtain unarchiver: " + e.getMessage(),
+                                                                  e );
                             }
 
                             /*
@@ -560,7 +584,7 @@
                             {
                                 String[] securityFiles = {"*.RSA", "*.DSA", "*.SF", "*.rsa", "*.dsa", "*.sf"};
                                 org.apache.maven.shared.model.fileset.FileSet securityFileSet =
-                                    new org.apache.maven.shared.model.fileset.FileSet();
+                                new org.apache.maven.shared.model.fileset.FileSet();
                                 securityFileSet.setDirectory( tempLocation.getAbsolutePath() + "/META-INF/" );
 
                                 for ( int sfsi = 0; sfsi < securityFiles.length; sfsi++ )
@@ -576,12 +600,32 @@
                                 catch ( IOException e )
                                 {
                                     throw new MojoExecutionException(
-                                        "Failed to delete security files: " + e.getMessage(), e );
+                                                                    "Failed to delete security files: " + e.getMessage(), e );
                                 }
                             }
                         }
 
-                        addDirectory( archiver, tempLocation, output, null, FileUtils.getDefaultExcludesAsList() );
+                        String[] includesArray = (String[]) unpack.getIncludes().toArray( EMPTY_STRING_ARRAY );
+                        if ( includesArray.length == 0 )
+                        {
+                            // include everything
+                            includesArray = null;
+                        }
+
+                        // TODO: default excludes should be in the archiver?
+                        List excludesList = unpack.getExcludes();
+                        excludesList.addAll( FileUtils.getDefaultExcludesAsList() );
+
+                        MapperUtil mapper = new MapperUtil( binaries.getMapper() );
+                        try
+                        {
+                            addDirectoryWithMapper( archiver, tempLocation, output, includesArray, excludesList, mapper );
+                        }
+                        catch ( Exception e )
+                        {
+                            throw new MojoExecutionException(
+                                                            "Error adding '" + tempLocation.getAbsolutePath() + "' to archive: " + e.getMessage(), e );
+                        }
                     }
                     else
                     {
@@ -589,8 +633,8 @@
                         {
                             String outputFileNameMapping = binaries.getOutputFileNameMapping();
 
-                            archiver.addFile( moduleArtifact.getFile(), output +
-                                evaluateFileNameMapping( moduleArtifact, outputFileNameMapping ) );
+                            archiver.addFile( moduleArtifact.getFile(),
+                                              output + evaluateFileNameMapping( moduleArtifact, outputFileNameMapping ) );
 
                             if ( binaries.isIncludeDependencies() )
                             {
@@ -599,13 +643,14 @@
                                     Artifact dependencyArtifact = (Artifact) artifacts.next();
 
                                     archiver.addFile( dependencyArtifact.getFile(), output +
-                                        evaluateFileNameMapping( dependencyArtifact, outputFileNameMapping ) );
+                                                      evaluateFileNameMapping( dependencyArtifact, outputFileNameMapping ) );
                                 }
                             }
                         }
                         catch ( ArchiverException e )
                         {
-                            throw new MojoExecutionException( "Error adding file to archive: " + e.getMessage(), e );
+                            throw new MojoExecutionException( "Error adding file to archive: " + e.getMessage(),
+                                                              e );
                         }
                     }
                 }
@@ -631,7 +676,7 @@
     }
 
     private static String evaluateFileNameMapping( Artifact artifact, String mapping )
-        throws MojoExecutionException
+    throws MojoExecutionException
     {
         String fileNameMapping = mapping;
         //insert the classifier if exist
@@ -699,7 +744,7 @@
     }
 
     protected List readAssemblies()
-        throws MojoFailureException, MojoExecutionException
+    throws MojoFailureException, MojoExecutionException
     {
         List assemblies = new ArrayList();
 
@@ -766,7 +811,7 @@
     }
 
     private Assembly getAssembly( String ref )
-        throws MojoFailureException, MojoExecutionException
+    throws MojoFailureException, MojoExecutionException
     {
         InputStream resourceAsStream = getClass().getResourceAsStream( "/assemblies/" + ref + ".xml" );
         if ( resourceAsStream == null )
@@ -777,7 +822,7 @@
     }
 
     private Assembly getAssembly( File file )
-        throws MojoFailureException, MojoExecutionException
+    throws MojoFailureException, MojoExecutionException
     {
         Reader r;
         try
@@ -793,7 +838,7 @@
     }
 
     private Assembly getAssembly( Reader reader )
-        throws MojoFailureException, MojoExecutionException
+    throws MojoFailureException, MojoExecutionException
     {
         Assembly assembly;
 
@@ -843,7 +888,7 @@
      * @throws MojoExecutionException
      */
     private void appendComponentsToMainAssembly( Assembly assembly )
-        throws MojoFailureException, MojoExecutionException
+    throws MojoFailureException, MojoExecutionException
     {
         List componentDescriptorFiles = assembly.getComponentDescriptors();
 
@@ -894,7 +939,7 @@
      * @throws MojoExecutionException
      */
     private Component getComponent( String filePath )
-        throws MojoExecutionException, MojoFailureException
+    throws MojoExecutionException, MojoFailureException
     {
         File componentDescriptor = new File( this.project.getBasedir() + "/" + filePath );
 
@@ -918,7 +963,7 @@
      * @param reader
      */
     private Component getComponent( Reader reader )
-        throws MojoExecutionException
+    throws MojoExecutionException
     {
         Component component;
         try
@@ -950,7 +995,7 @@
      * @param includeBaseDirectory
      */
     protected void processDependencySets( Archiver archiver, List dependencySets, boolean includeBaseDirectory )
-        throws MojoExecutionException
+    throws MojoExecutionException
     {
         for ( Iterator i = dependencySets.iterator(); i.hasNext(); )
         {
@@ -963,23 +1008,24 @@
             archiver.setDefaultFileMode( Integer.parseInt( dependencySet.getFileMode(), 8 ) );
 
             getLog().debug( "DependencySet[" + output + "]" + " dir perms: " +
-                Integer.toString( archiver.getDefaultDirectoryMode(), 8 ) + " file perms: " +
-                Integer.toString( archiver.getDefaultFileMode(), 8 ) );
+                            Integer.toString( archiver.getDefaultDirectoryMode(), 8 ) + " file perms: " +
+                            Integer.toString( archiver.getDefaultFileMode(), 8 ) );
 
             Set allDependencyArtifacts = ProjectUtils.getDependencies( getExecutedProject() );
             Set dependencyArtifacts = new HashSet( allDependencyArtifacts );
 
             AssemblyScopeArtifactFilter scopeFilter = new AssemblyScopeArtifactFilter( dependencySet.getScope() );
 
-            FilterUtils.filterArtifacts( dependencyArtifacts, dependencySet.getIncludes(), dependencySet.getExcludes(),
-                                         true, Collections.singletonList( scopeFilter ) );
+            FilterUtils.filterArtifacts( dependencyArtifacts, dependencySet.getIncludes(), dependencySet.getExcludes(), true, Collections.singletonList( scopeFilter ) );
 
             for ( Iterator j = dependencyArtifacts.iterator(); j.hasNext(); )
             {
                 Artifact artifact = (Artifact) j.next();
 
-                String fileNameMapping = evaluateFileNameMapping( artifact, dependencySet.getOutputFileNameMapping() );
-                if ( dependencySet.isUnpack() )
+                String fileNameMapping =
+                evaluateFileNameMapping( artifact, dependencySet.getOutputFileNameMapping() );
+                Unpack unpack = dependencySet.getUnpack();
+                if ( unpack != null )
                 {
                     // TODO: something like zipfileset in plexus-archiver
                     //                        archiver.addJar(  )
@@ -1005,7 +1051,7 @@
                         catch ( NoSuchArchiverException e )
                         {
                             throw new MojoExecutionException(
-                                "Unable to obtain unarchiver for file '" + artifact.getFile() + "'" );
+                                                            "Unable to obtain unarchiver for file '" + artifact.getFile() + "'" );
                         }
 
                         /*
@@ -1016,7 +1062,7 @@
                         {
                             String[] securityFiles = {"*.RSA", "*.DSA", "*.SF", "*.rsa", "*.dsa", "*.sf"};
                             org.apache.maven.shared.model.fileset.FileSet securityFileSet =
-                                new org.apache.maven.shared.model.fileset.FileSet();
+                            new org.apache.maven.shared.model.fileset.FileSet();
                             securityFileSet.setDirectory( tempLocation.getAbsolutePath() + "/META-INF/" );
 
                             for ( int sfsi = 0; sfsi < securityFiles.length; sfsi++ )
@@ -1031,13 +1077,33 @@
                             }
                             catch ( IOException e )
                             {
-                                throw new MojoExecutionException( "Failed to delete security files: " + e.getMessage(),
-                                                                  e );
+                                throw new MojoExecutionException(
+                                                                "Failed to delete security files: " + e.getMessage(), e );
                             }
                         }
                     }
 
-                    addDirectory( archiver, tempLocation, output, null, FileUtils.getDefaultExcludesAsList() );
+                    String[] includes = (String[]) unpack.getIncludes().toArray( EMPTY_STRING_ARRAY );
+                    if ( includes.length == 0 )
+                    {
+                        // include everything
+                        includes = null;
+                    }
+
+                    // TODO: default excludes should be in the archiver?
+                    List excludesList = unpack.getExcludes();
+                    excludesList.addAll( FileUtils.getDefaultExcludesAsList() );
+
+                    MapperUtil mapper = new MapperUtil( dependencySet.getMapper() );
+                    try
+                    {
+                        addDirectoryWithMapper( archiver, tempLocation, output, includes, excludesList, mapper );
+                    }
+                    catch ( Exception e )
+                    {
+                        throw new MojoExecutionException(
+                                                        "Error adding '" + tempLocation.getAbsolutePath() + "' to archive: " + e.getMessage(), e );
+                    }
                 }
                 else
                 {
@@ -1048,7 +1114,7 @@
                     catch ( ArchiverException e )
                     {
                         throw new MojoExecutionException(
-                            "Error adding file '" + artifact.getFile() + "' to archive: " + e.getMessage(), e );
+                                                        "Error adding file '" + artifact.getFile() + "' to archive: " + e.getMessage(), e );
                     }
                 }
             }
@@ -1066,44 +1132,6 @@
         }
     }
 
-    private void addDirectory( Archiver archiver, File directory, String output, String[] includes, List excludes )
-        throws MojoExecutionException
-    {
-        if ( directory.exists() )
-        {
-            List adaptedExcludes = excludes;
-
-            // TODO: more robust set of filters on added files in the archiver
-            File componentsXml = new File( directory, ComponentsXmlArchiverFileFilter.COMPONENTS_XML_PATH );
-            if ( componentsXml.exists() )
-            {
-                try
-                {
-                    componentsXmlFilter.addComponentsXml( componentsXml );
-                }
-                catch ( IOException e )
-                {
-                    throw new MojoExecutionException( "Error reading components.xml to merge: " + e.getMessage(), e );
-                }
-                catch ( XmlPullParserException e )
-                {
-                    throw new MojoExecutionException( "Error reading components.xml to merge: " + e.getMessage(), e );
-                }
-                adaptedExcludes = new ArrayList( excludes );
-                adaptedExcludes.add( ComponentsXmlArchiverFileFilter.COMPONENTS_XML_PATH );
-            }
-
-            try
-            {
-                archiver.addDirectory( directory, output, includes,
-                                       (String[]) adaptedExcludes.toArray( EMPTY_STRING_ARRAY ) );
-            }
-            catch ( ArchiverException e )
-            {
-                throw new MojoExecutionException( "Error adding directory to archive: " + e.getMessage(), e );
-            }
-        }
-    }
 
     /**
      * Process Files that will be included in the distribution.
@@ -1113,7 +1141,7 @@
      * @param includeBaseDirecetory
      */
     protected void processFileSets( Archiver archiver, List fileSets, boolean includeBaseDirecetory )
-        throws MojoExecutionException, MojoFailureException
+    throws MojoExecutionException, MojoFailureException
     {
         for ( Iterator i = fileSets.iterator(); i.hasNext(); )
         {
@@ -1136,9 +1164,9 @@
             archiver.setDefaultFileMode( Integer.parseInt( fileSet.getFileMode(), 8 ) );
 
             getLog().debug( "FileSet[" + output + "]" + " dir perms: " +
-                Integer.toString( archiver.getDefaultDirectoryMode(), 8 ) + " file perms: " +
-                Integer.toString( archiver.getDefaultFileMode(), 8 ) +
-                ( fileSet.getLineEnding() == null ? "" : " lineEndings: " + fileSet.getLineEnding() ) );
+                    Integer.toString( archiver.getDefaultDirectoryMode(), 8 ) + " file perms: " +
+                    Integer.toString( archiver.getDefaultFileMode(), 8 ) +
+                    ( fileSet.getLineEnding() == null ? "" : " lineEndings: " + fileSet.getLineEnding() ) );
 
             if ( directory == null )
             {
@@ -1179,12 +1207,12 @@
                 if ( ! archiveBaseDirectory.exists() )
                 {
                     throw new MojoFailureException(
-                        "The archive base directory '" + archiveBaseDirectory.getAbsolutePath() + "' does not exist" );
+                                                  "The archive base directory '" + archiveBaseDirectory.getAbsolutePath() + "' does not exist" );
                 }
                 if ( ! archiveBaseDirectory.isDirectory() )
                 {
                     throw new MojoFailureException( "The archive base directory '" +
-                        archiveBaseDirectory.getAbsolutePath() + "' exists, but it is not a directory" );
+                                                    archiveBaseDirectory.getAbsolutePath() + "' exists, but it is not a directory" );
                 }
                 archiveBaseDir = new File( archiveBaseDirectory, directory );
             }
@@ -1204,7 +1232,16 @@
                     archiveBaseDir = tmpDir;
                 }
                 getLog().debug( "Archive base directory: '" + archiveBaseDir.getAbsolutePath() + "'" );
-                addDirectory( archiver, archiveBaseDir, output, includes, excludesList );
+                MapperUtil mapper = new MapperUtil( fileSet.getMapper() );
+                try
+                {
+                    addDirectoryWithMapper( archiver, archiveBaseDir, output, includes, excludesList, mapper);
+                }
+                catch ( Exception e )
+                {
+                    throw new MojoExecutionException(
+                                                    "Error adding '" + archiveBaseDir.getAbsolutePath() + "' to archive: " + e.getMessage(), e );
+                }
             }
         }
     }
@@ -1216,17 +1253,17 @@
      * @param fileList
      */
     protected void processFileList( Archiver archiver, List fileList, boolean includeBaseDirecetory )
-        throws MojoExecutionException, MojoFailureException
+    throws MojoExecutionException, MojoFailureException
     {
         for ( Iterator i = fileList.iterator(); i.hasNext(); )
         {
             FileItem fileItem = (FileItem) i.next();
 
             //ensure source file is in absolute path for reactor build to work
-            File source = new File( fileItem.getSource() );
+            File source = new File ( fileItem.getSource() );
             if ( ! source.isAbsolute() )
             {
-                source = new File( this.basedir, fileItem.getSource() );
+                source =  new File( this.basedir, fileItem.getSource() );
             }
 
             if ( fileItem.isFiltered() )
@@ -1303,7 +1340,7 @@
      *
      */
     private static String evaluateFileNameMapping( String expression, Artifact artifact )
-        throws MojoExecutionException
+    throws MojoExecutionException
     {
         String value = expression;
 
@@ -1322,7 +1359,7 @@
             catch ( Exception e )
             {
                 throw new MojoExecutionException(
-                    "Cannot evaluate filenameMapping: '" + mat.group( 1 ) + "': " + e.getMessage(), e );
+                                                "Cannot evaluate filenameMapping: '" + mat.group( 1 ) + "': " + e.getMessage(), e );
             }
             String right = mat.group( 3 );
 
@@ -1404,7 +1441,7 @@
      *
      */
     private Archiver createArchiver( String format )
-        throws ArchiverException, NoSuchArchiverException
+    throws ArchiverException, NoSuchArchiverException
     {
         Archiver archiver;
         if ( format.startsWith( "tar" ) )
@@ -1454,7 +1491,7 @@
     }
 
     private void copyReplacingLineEndings( File source, File dest, String lineEndings )
-        throws IOException
+    throws IOException
     {
         getLog().debug( "Copying while replacing line endings: " + source + " to " + dest );
 
@@ -1488,7 +1525,7 @@
 
     private void copySetReplacingLineEndings( File archiveBaseDir, File tmpDir, String[] includes, String[] excludes,
                                               String lineEnding )
-        throws MojoExecutionException
+    throws MojoExecutionException
     {
         DirectoryScanner scanner = new DirectoryScanner();
         scanner.setBasedir( archiveBaseDir.getAbsolutePath() );
@@ -1524,7 +1561,7 @@
     }
 
     private static String getLineEndingCharacters( String lineEnding )
-        throws MojoFailureException
+    throws MojoFailureException
     {
         String value = lineEnding;
         if ( lineEnding != null )
@@ -1551,12 +1588,12 @@
     }
 
     private void includeSiteInAssembly( Assembly assembly )
-        throws MojoFailureException
+    throws MojoFailureException
     {
         if ( !siteDirectory.exists() )
         {
             throw new MojoFailureException(
-                "site did not exist in the target directory - please run site:site before creating the assembly" );
+                                          "site did not exist in the target directory - please run site:site before creating the assembly" );
         }
 
         getLog().info( "Adding site directory to assembly : " + siteDirectory );
@@ -1572,7 +1609,7 @@
 
     //@todo should only run once or know when it has already initialized
     private void initializeFiltering()
-        throws MojoExecutionException
+    throws MojoExecutionException
     {
         getLog().info( "Initializing assembly filters..." );
 
@@ -1603,7 +1640,7 @@
     }
 
     private File filterFile( File file )
-        throws MojoExecutionException
+    throws MojoExecutionException
     {
         initializeFiltering();
 
@@ -1627,7 +1664,7 @@
             Reader reader = new InterpolationFilterReader( fileReader, filterProperties, "${", "}" );
 
             BufferedReader in = new BufferedReader( new InterpolationFilterReader( reader, new ReflectionProperties(
-                project, isPropertiesFile ), "${", "}" ) );
+                                                                                                                   project, isPropertiesFile ), "${", "}" ) );
 
             Writer fileWriter = null;
             try
@@ -1664,4 +1701,215 @@
 
         return tempFilterFile;
     }
+
+    // Copied from AbstractArchiver.addDirectory
+    // The mapper passed to this is invoked before the file is added to the archiver.
+    public void addDirectoryWithMapper( Archiver archiver, File directory, String prefix, String[] includes, List excludes, MapperUtil mapper )
+    throws Exception, ArchiverException, IOException 
+    {
+        FileNameMapper fileMapper;
+        DirectoryScanner scanner = new DirectoryScanner();
+        try
+        {
+            fileMapper = mapper.getImplementation();
+        }
+        catch ( Exception e )
+        {
+            throw e;
+        }
+
+        if ( !directory.isDirectory() )
+        {
+            throw new ArchiverException( directory.getAbsolutePath() + " isn't a directory." );
+        }
+
+        if ( includes != null )
+        {
+            scanner.setIncludes( includes );
+        }
+
+        if ( excludes != null )
+        {
+            try
+            {
+                String[] excludesArray = handleComponentsXML(directory, excludes);
+
+                if ( excludesArray != null )
+                {
+                    scanner.setExcludes( excludesArray );
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+
+        String basedir = directory.getAbsolutePath();
+        scanner.setBasedir( basedir );
+        scanner.scan();
+
+
+        if ( archiver.getIncludeEmptyDirs() )
+        {
+            String [] dirs = scanner.getIncludedDirectories();
+
+            for ( int i = 0; i < dirs.length; i++ )
+            {
+                String sourceDir = dirs[i].replace( '\\', '/' );
+
+                File dir = new File( basedir, sourceDir );
+                String[] contents = dir.list();
+                if ( contents == null  || contents.length > 0 )
+                {
+                    getLog().debug( dir.getAbsolutePath() + " not empty. Skipping it" );
+                    continue;
+                }
+
+                String fileName = fileMapper.mapFileName( sourceDir );
+
+                String targetDir = ( prefix == null ? "" : prefix ) + fileName;
+
+                archiver.addDirectory(new File( basedir, sourceDir ), targetDir);
+            }
+        }
+
+        String[] files = scanner.getIncludedFiles();
+
+        for ( int i = 0; i < files.length; i++ )
+        {
+            String sourceFile = files[i].replace( '\\', '/' );
+
+            String fileName = fileMapper.mapFileName( sourceFile );
+
+            String targetFile = ( prefix == null ? "" : prefix ) + fileName;
+
+            archiver.addFile( new File(basedir, sourceFile), targetFile );
+        }
+
+    }
+
+    private String[] handleComponentsXML( File directory, List excludes )
+    throws IOException
+    {
+        List adaptedExcludes = excludes;
+
+        // TODO: more robust set of filters on added files in the archiver
+        File componentsXml = new File( directory, ComponentsXmlArchiverFileFilter.COMPONENTS_XML_PATH );
+        if ( componentsXml.exists() )
+        {
+            try
+            {
+                componentsXmlFilter.addComponentsXml( componentsXml );
+            }
+            catch ( IOException e )
+            {
+                throw new IOException( "Error reading components.xml to merge: " + e.getMessage() );
+            }
+            catch ( XmlPullParserException e )
+            {
+                throw new IOException( "Error reading components.xml to merge: " + e.getMessage() );
+            }
+            adaptedExcludes = new ArrayList( excludes );
+            adaptedExcludes.add( ComponentsXmlArchiverFileFilter.COMPONENTS_XML_PATH );
+        }
+
+        return(String[]) adaptedExcludes.toArray( EMPTY_STRING_ARRAY );
+    }
+
+    protected void setAppendAssemblyId( boolean appendAssemblyId )
+    {
+        this.appendAssemblyId = appendAssemblyId;
+    }
+
+    protected void setArchive( MavenArchiveConfiguration archive )
+    {
+        this.archive = archive;
+    }
+
+    protected void setArchiveBaseDirectory( File archiveBaseDirectory )
+    {
+        this.archiveBaseDirectory = archiveBaseDirectory;
+    }
+
+    protected void setBasedir( File basedir )
+    {
+        this.basedir = basedir;
+    }
+
+    protected void setComponentsXmlFilter( ComponentsXmlArchiverFileFilter componentsXmlFilter )
+    {
+        this.componentsXmlFilter = componentsXmlFilter;
+    }
+
+    /**
+     * @deprecated Use setDescriptors(..) instead.
+     * @param descriptor
+     */
+    protected void setDescriptor( File descriptor )
+    {
+        this.descriptor = descriptor;
+    }
+
+    protected void setDescriptorId( String descriptorId )
+    {
+        this.descriptorId = descriptorId;
+    }
+
+    protected void setDescriptorRefs( String[] descriptorRefs )
+    {
+        this.descriptorRefs = descriptorRefs;
+    }
+
+    protected void setDescriptors( File[] descriptors )
+    {
+        this.descriptors = descriptors;
+    }
+
+    protected void setDescriptorSourceDirectory( File descriptorSourceDirectory )
+    {
+        this.descriptorSourceDirectory = descriptorSourceDirectory;
+    }
+
+    protected void setFilterProperties( Properties filterProperties )
+    {
+        this.filterProperties = filterProperties;
+    }
+
+    protected void setFilters( List filters )
+    {
+        this.filters = filters;
+    }
+
+    protected void setIncludeSite( boolean includeSite )
+    {
+        this.includeSite = includeSite;
+    }
+
+    protected void setIntermediaryAssembly( boolean intermediaryAssembly )
+    {
+        this.intermediaryAssembly = intermediaryAssembly;
+    }
+
+    protected void setProjectHelper( MavenProjectHelper projectHelper )
+    {
+        this.projectHelper = projectHelper;
+    }
+
+    protected void setRepositoryAssembler( RepositoryAssembler repositoryAssembler )
+    {
+        this.repositoryAssembler = repositoryAssembler;
+    }
+
+    protected void setSiteDirectory( File siteDirectory )
+    {
+        this.siteDirectory = siteDirectory;
+    }
+
+    protected void setTarLongFileMode( String tarLongFileMode )
+    {
+        this.tarLongFileMode = tarLongFileMode;
+    }
+
+
 }
diff --git a/src/main/java/org/apache/maven/plugin/assembly/AbstractUnpackingMojo.java b/src/main/java/org/apache/maven/plugin/assembly/AbstractUnpackingMojo.java
index 7de6014..9593186 100644
--- a/src/main/java/org/apache/maven/plugin/assembly/AbstractUnpackingMojo.java
+++ b/src/main/java/org/apache/maven/plugin/assembly/AbstractUnpackingMojo.java
@@ -147,4 +147,49 @@
     {
         return classifier;
     }
+
+    protected void setArchiverManager( ArchiverManager archiverManager )
+    {
+        this.archiverManager = archiverManager;
+    }
+
+    protected void setArtifactResolver( ArtifactResolver artifactResolver )
+    {
+        this.artifactResolver = artifactResolver;
+    }
+
+    protected void setClassifier( String classifier )
+    {
+        this.classifier = classifier;
+    }
+
+    protected void setFinalName( String finalName )
+    {
+        this.finalName = finalName;
+    }
+
+    protected void setLocalRepository( ArtifactRepository localRepository )
+    {
+        this.localRepository = localRepository;
+    }
+
+    protected void setOutputDirectory( File outputDirectory )
+    {
+        this.outputDirectory = outputDirectory;
+    }
+
+    protected void setProject( MavenProject project )
+    {
+        this.project = project;
+    }
+
+    protected void setReactorProjects( List reactorProjects )
+    {
+        this.reactorProjects = reactorProjects;
+    }
+
+    protected void setWorkDirectory( File workDirectory )
+    {
+        this.workDirectory = workDirectory;
+    }
 }
diff --git a/src/main/java/org/apache/maven/plugin/assembly/DirectoryMojo.java b/src/main/java/org/apache/maven/plugin/assembly/DirectoryMojo.java
index cf94a15..99af8d4 100644
--- a/src/main/java/org/apache/maven/plugin/assembly/DirectoryMojo.java
+++ b/src/main/java/org/apache/maven/plugin/assembly/DirectoryMojo.java
@@ -40,4 +40,9 @@
     {
         return executedProject;
     }
+
+    protected void setExecutedProject( MavenProject executedProject )
+    {
+        this.executedProject = executedProject;
+    }
 }
diff --git a/src/main/java/org/apache/maven/plugin/assembly/mappers/FileNameMapper.java b/src/main/java/org/apache/maven/plugin/assembly/mappers/FileNameMapper.java
new file mode 100644
index 0000000..7d6f705
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/assembly/mappers/FileNameMapper.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright  2000,2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.maven.plugin.assembly.mappers;
+
+/**
+ * Interface to be used by SourceFileScanner.
+ *
+ * <p>Used to find the name of the target file(s) corresponding to a
+ * source file.</p>
+ *
+ * <p>The rule by which the file names are transformed is specified
+ * via the setFrom and setTo methods. The exact meaning of these is
+ * implementation dependent.</p>
+ *
+ */
+public interface FileNameMapper {
+
+    /**
+     * Sets the from part of the transformation rule.
+     */
+    void setFrom(String from);
+
+    /**
+     * Sets the to part of the transformation rule.
+     */
+    void setTo(String to);
+
+    /**
+     * Returns the target filename for the
+     * given source file.
+     *
+     * <p>if the given rule doesn't apply to the source file,
+     * implementation must return null. SourceFileScanner will then
+     * omit the source file in question.</p>
+     *
+     * @param sourceFileName the name of the source file relative to
+     *                       some given basedirectory.
+     */
+    String mapFileName(String sourceFileName);
+}
diff --git a/src/main/java/org/apache/maven/plugin/assembly/mappers/FlatFileNameMapper.java b/src/main/java/org/apache/maven/plugin/assembly/mappers/FlatFileNameMapper.java
new file mode 100644
index 0000000..eba8a54
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/assembly/mappers/FlatFileNameMapper.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright  2000,2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.maven.plugin.assembly.mappers;
+
+/**
+ * Implementation of FileNameMapper that always returns the source
+ * file name without any leading directory information.
+ *
+ * <p>This is the default FileNameMapper for the copy and move
+ * tasks if the flatten attribute has been set.</p>
+ *
+ */
+public class FlatFileNameMapper implements FileNameMapper {
+
+    /**
+     * Ignored.
+     */
+    public void setFrom(String from) {
+    }
+
+    /**
+     * Ignored.
+     */
+    public void setTo(String to) {
+    }
+
+    /**
+     * Returns an one-element array containing the source file name
+     * without any leading directory information.
+     */
+    public String mapFileName(String sourceFileName) {
+        return new String( new java.io.File(sourceFileName).getName() );
+    }
+}
diff --git a/src/main/java/org/apache/maven/plugin/assembly/mappers/GlobPatternMapper.java b/src/main/java/org/apache/maven/plugin/assembly/mappers/GlobPatternMapper.java
new file mode 100644
index 0000000..669b5f1
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/assembly/mappers/GlobPatternMapper.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright  2000,2002,2004-2005 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.maven.plugin.assembly.mappers;
+
+/**
+ * Implementation of FileNameMapper that does simple wildcard pattern
+ * replacements.
+ *
+ * <p>This does simple translations like *.foo -> *.bar where the
+ * prefix to .foo will be left unchanged. It only handles a single *
+ * character, use regular expressions for more complicated
+ * situations.</p>
+ *
+ * <p>This is one of the more useful Mappers, it is used by javac for
+ * example.</p>
+ *
+ */
+public class GlobPatternMapper implements FileNameMapper {
+
+    /**
+     * Part of &quot;from&quot; pattern before the *.
+     */
+    protected String fromPrefix = null;
+
+    /**
+     * Part of &quot;from&quot; pattern after the *.
+     */
+    protected String fromPostfix = null;
+
+    /**
+     * Length of the prefix (&quot;from&quot; pattern).
+     */
+    protected int prefixLength;
+
+    /**
+     * Length of the postfix (&quot;from&quot; pattern).
+     */
+    protected int postfixLength;
+
+    /**
+     * Part of &quot;to&quot; pattern before the *.
+     */
+    protected String toPrefix = null;
+
+    /**
+     * Part of &quot;to&quot; pattern after the *.
+     */
+    protected String toPostfix = null;
+
+    private boolean handleDirSep = false;
+    private boolean caseSensitive = true;
+
+    /**
+     * Attribute specifing whether to ignore the difference
+     * between / and \ (the two common directory characters).
+     * @param handleDirSep a boolean, default is false.
+     * @since Ant 1.6.3
+     */
+    public void setHandleDirSep(boolean handleDirSep) {
+        this.handleDirSep = handleDirSep;
+    }
+
+    /**
+     * Attribute specifing whether to ignore the case difference
+     * in the names.
+     *
+     * @param caseSensitive a boolean, default is false.
+     * @since Ant 1.6.3
+     */
+    public void setCaseSensitive(boolean caseSensitive) {
+        this.caseSensitive = caseSensitive;
+    }
+
+    /**
+     * Sets the &quot;from&quot; pattern. Required.
+     * @param from a string
+     */
+    public void setFrom(String from) {
+        int index = from.lastIndexOf("*");
+        if (index == -1) {
+            fromPrefix = from;
+            fromPostfix = "";
+        } else {
+            fromPrefix = from.substring(0, index);
+            fromPostfix = from.substring(index + 1);
+        }
+        prefixLength = fromPrefix.length();
+        postfixLength = fromPostfix.length();
+    }
+
+    /**
+     * Sets the &quot;to&quot; pattern. Required.
+     * @param to a string
+     */
+    public void setTo(String to) {
+        int index = to.lastIndexOf("*");
+        if (index == -1) {
+            toPrefix = to;
+            toPostfix = "";
+        } else {
+            toPrefix = to.substring(0, index);
+            toPostfix = to.substring(index + 1);
+        }
+    }
+
+    /**
+     * Returns null if the source file name doesn't match the
+     * &quot;from&quot; pattern, an one-element array containing the
+     * translated file otherwise.
+     * @param sourceFileName the filename to map
+     * @return a list of converted filenames
+     */
+    public String mapFileName(String sourceFileName) {
+        if (fromPrefix == null
+            || !modifyName(sourceFileName).startsWith(modifyName(fromPrefix))
+            || !modifyName(sourceFileName).endsWith(modifyName(fromPostfix))) {
+            return null;
+        }
+        return new String (toPrefix
+                                 + extractVariablePart(sourceFileName)
+                                 + toPostfix);
+    }
+
+    /**
+     * Returns the part of the given string that matches the * in the
+     * &quot;from&quot; pattern.
+     * @param name the source file name
+     * @return the variable part of the name
+     */
+    protected String extractVariablePart(String name) {
+        return name.substring(prefixLength,
+                              name.length() - postfixLength);
+    }
+
+    /**
+     * modify string based on dir char mapping and case sensitivity
+     * @param name the name to convert
+     * @return the converted name
+     */
+    private String modifyName(String name) {
+        if (!caseSensitive) {
+            name = name.toLowerCase();
+        }
+        if (handleDirSep) {
+            if (name.indexOf('\\') != -1) {
+                name = name.replace('\\', '/');
+            }
+        }
+        return name;
+    }
+}
diff --git a/src/main/java/org/apache/maven/plugin/assembly/mappers/IdentityMapper.java b/src/main/java/org/apache/maven/plugin/assembly/mappers/IdentityMapper.java
new file mode 100644
index 0000000..78764c1
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/assembly/mappers/IdentityMapper.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright  2000,2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.maven.plugin.assembly.mappers;
+
+/**
+ * Implementation of FileNameMapper that always returns the source file name.
+ *
+ * <p>This is the default FileNameMapper for the copy and move
+ * tasks.</p>
+ *
+ */
+public class IdentityMapper implements FileNameMapper {
+
+    /**
+     * Ignored.
+     */
+    public void setFrom(String from) {
+    }
+
+    /**
+     * Ignored.
+     */
+    public void setTo(String to) {
+    }
+
+    /**
+     * Returns an one-element array containing the source file name.
+     */
+    public String mapFileName(String sourceFileName) {
+        return sourceFileName;
+    }
+}
diff --git a/src/main/java/org/apache/maven/plugin/assembly/mappers/MapperUtil.java b/src/main/java/org/apache/maven/plugin/assembly/mappers/MapperUtil.java
new file mode 100644
index 0000000..c536066
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/assembly/mappers/MapperUtil.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright  2000-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.maven.plugin.assembly.mappers;
+
+import java.util.Enumeration;
+import java.util.Properties;
+import org.apache.maven.plugins.assembly.model.Mapper;
+import org.apache.maven.plugin.assembly.mappers.FileNameMapper;
+
+/**
+ * Element to define a FileNameMapper.
+ *
+ */
+public class MapperUtil {
+
+    private Properties implementations;
+    protected String from = null;
+    protected String to = null;
+    protected String type = "identity";
+    protected String classname = null;
+
+
+    /**
+     * Construct a new <CODE>MapperUtil</CODE> element.
+     * @param p   the owning Ant <CODE>Project</CODE>.
+     */
+    public MapperUtil(Mapper mapper) {
+        initializeProperties();
+        this.type = mapper.getType();
+        this.from = mapper.getFrom();
+        this.to = mapper.getTo();
+        this.classname = mapper.getClassname();
+    }
+
+
+    /**
+     * Initializes a properties object to store the built-in classnames.
+     */
+    public void initializeProperties () {
+        implementations = new Properties();
+        implementations.setProperty("identity",
+                                    "org.apache.maven.plugin.assembly.mappers.IdentityMapper");
+        implementations.setProperty("flatten",
+                                    "org.apache.maven.plugin.assembly.mappers.FlatFileNameMapper");
+        implementations.setProperty("glob",
+                                    "org.apache.maven.plugin.assembly.mappers.GlobPatternMapper");
+        implementations.setProperty("merge",
+                                    "org.apache.maven.plugin.assembly.mappers.MergingMapper");
+        implementations.setProperty("regexp",
+                                    "org.apache.maven.plugin.assembly.mappers.RegexpPatternMapper");
+        implementations.setProperty("package",
+                                    "org.apache.maven.plugin.assembly.mappers.PackageNameMapper");
+        implementations.setProperty("unpackage",
+                                    "org.apache.maven.plugin.assembly.mappers.UnPackageNameMapper");
+    }
+
+
+
+
+
+    /**
+     * Returns a fully configured FileNameMapper implementation.
+     */
+    public FileNameMapper getImplementation() throws Exception {
+        if (type == null && classname == null) {
+            throw new Exception(
+                               "nested mapper or "
+                               + "one of the attributes type or classname is required");
+        }
+
+        if (type != null && classname != null) {
+            throw new Exception(
+                               "must not specify both type and classname attribute");
+        }
+        if (type != null) {
+            classname = implementations.getProperty(type);
+        }
+
+        try {
+            FileNameMapper m
+            = (FileNameMapper) Class.forName(classname).newInstance();
+
+            m.setFrom(from);
+            m.setTo(to);
+
+            return m;
+        }
+        catch (ClassNotFoundException cnfe) {
+            throw cnfe;
+        }
+        catch (Throwable t) {
+            throw new Exception(t);
+        }
+    }
+
+
+
+    public Enumeration getTypes() {
+        return implementations.propertyNames();
+    }
+
+    public Properties getImplementations(){
+        return this.implementations;
+    }
+
+
+}
diff --git a/src/main/java/org/apache/maven/plugin/assembly/mappers/MergingMapper.java b/src/main/java/org/apache/maven/plugin/assembly/mappers/MergingMapper.java
new file mode 100644
index 0000000..9826788
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/assembly/mappers/MergingMapper.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright  2000,2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.maven.plugin.assembly.mappers;
+
+/**
+ * Implementation of FileNameMapper that always returns the same
+ * target file name.
+ *
+ * <p>This is the default FileNameMapper for the archiving tasks and
+ * uptodate.</p>
+ *
+ */
+public class MergingMapper implements FileNameMapper {
+    protected String mergedFile = null;
+
+    /**
+     * Ignored.
+     */
+    public void setFrom(String from) {
+    }
+
+    /**
+     * Sets the name of the merged file.
+     */
+    public void setTo(String to) {
+        mergedFile = to;
+    }
+
+    /**
+     * Returns an one-element array containing the file name set via setTo.
+     */
+    public String mapFileName(String sourceFileName) {
+        return mergedFile;
+    }
+
+}
diff --git a/src/main/java/org/apache/maven/plugin/assembly/mappers/PackageNameMapper.java b/src/main/java/org/apache/maven/plugin/assembly/mappers/PackageNameMapper.java
new file mode 100644
index 0000000..c5e656e
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/assembly/mappers/PackageNameMapper.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright  2001-2002,2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.maven.plugin.assembly.mappers;
+
+import java.io.File;
+
+/**
+ * Maps directory name matches into a dotted package name. This is
+ * useful for matching JUnit test cases againt their XML formatter
+ * results.
+ * <pre>
+ * &lt;mapper classname="org.apache.tools.ant.util.PackageNameMapper"
+ *         from="*Test.java" to="${test.data.dir}/TEST-*Test.xml"/&gt;
+ * </pre>
+ *
+ */
+public class PackageNameMapper extends GlobPatternMapper {
+    /**
+     *  Returns the part of the given string that matches the * in the
+     *  &quot;from&quot; pattern replacing file separators with dots
+     *
+     *@param  name  Source filename
+     *@return       Replaced variable part
+     */
+    protected String extractVariablePart(String name) {
+        String var = name.substring(prefixLength,
+                name.length() - postfixLength);
+        return var.replace(File.separatorChar, '.');
+    }
+}
+
diff --git a/src/main/java/org/apache/maven/plugin/assembly/mappers/UnPackageNameMapper.java b/src/main/java/org/apache/maven/plugin/assembly/mappers/UnPackageNameMapper.java
new file mode 100644
index 0000000..ea12f4c
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/assembly/mappers/UnPackageNameMapper.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright  2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.maven.plugin.assembly.mappers;
+
+import java.io.File;
+
+/**
+ * Maps dotted package name matches to a directory name.
+ * This is the inverse of the package mapper.
+ * This is useful for matching XML formatter results against their JUnit test
+ * cases.
+ * <pre>
+ * &lt;mapper classname="org.apache.tools.ant.util.UnPackageNameMapper"
+ *         from="${test.data.dir}/TEST-*Test.xml" to="*Test.java"&gt;
+ * </pre>
+ *
+ *
+ */
+public class UnPackageNameMapper extends GlobPatternMapper {
+    /**
+     *  Returns the part of the given string that matches the * in the
+     *  &quot;from&quot; pattern replacing dots with file separators
+     *
+     *@param  name  Source filename
+     *@return       Replaced variable part
+     */
+    protected String extractVariablePart(String name) {
+        String var = name.substring(prefixLength,
+                name.length() - postfixLength);
+        return var.replace('.', File.separatorChar);
+    }
+}
+
diff --git a/src/main/mdo/component.mdo b/src/main/mdo/component.mdo
index 94e9899..400b61d 100755
--- a/src/main/mdo/component.mdo
+++ b/src/main/mdo/component.mdo
@@ -68,6 +68,17 @@
       <name>SetBase</name>
       <version>1.0.0</version>
       <fields>
+      <field>
+          <name>mapper</name>
+          <version>1.0.0</version>
+          <association>
+            <type>Mapper</type>
+          </association>
+          <defaultValue>new Mapper()</defaultValue>
+          <description>
+            Specifies the mapper used.
+          </description>
+        </field>
         <field>
           <name>outputDirectory</name>
           <version>1.0.0</version>
@@ -175,6 +186,59 @@
       </fields>
     </class>
     <class>
+      <name>Mapper</name>
+      <version>1.0.0</version>
+      <fields>
+        <field>
+          <name>type</name>
+          <version>1.0.0</version>
+          <type>String</type>
+          <defaultValue>identity</defaultValue>
+          <description>
+            specifies one of the built-in mapper implementations. A custom mapper may be specified by using the classname property.
+            If classname is being used, then the type should not be used.
+            <![CDATA[ 
+            Valid values:
+            <ul>
+              <li><b>"flatten"</b> - The target file name is identical to the source file name, with all leading directory information stripped off. Both to and from will be ignored </li>
+              <li><b>"glob"</b> - Both to and from define patterns that may contain at most one *. For each source file that matches the from pattern, a target file name will be constructed from the to pattern by substituting the * in the to pattern with the text that matches the * in the from pattern. Source file names that don't match the from pattern will be ignored/li>
+              <li><b>"regexp"</b> - Both to and from define regular expressions. If the source file name matches the from pattern, the target file name will be constructed from the to pattern, using \0 to \9 as back-references for the full match (\0) or the matches of the subexpressions in parentheses. Source files not matching the from pattern will be ignored.</li>
+              <li><b>"merge"</b> - The target file name will always be the same, as defined by to. from will be ignored</li>
+              <li><b>"package"</b> - Sharing the same syntax as the glob mapper, the package mapper replaces directory separators found in the matched source pattern with dots in the target pattern placeholder. This mapper is particularly useful in combination with <uptodate> and <junit> output. </li>
+              <li><b>"unpackage"</b> - This mapper is the inverse of the package mapper. It replaces the dots in a package name with directory separators. This is useful for matching XML formatter results against their JUnit test test cases. The mapper shares the sample syntax as the glob mapper. </li>
+            </ul>
+            ]]>
+          </description>
+          <required>true</required>
+        </field>
+        <field>
+          <name>from</name>
+          <version>1.0.0</version>
+          <type>String</type>
+          <description>
+          the from attribute for the given implementation. Depends on the implementation
+          </description>
+        </field>
+        <field>
+          <name>to</name>
+          <version>1.0.0</version>
+          <type>String</type>
+          <description>
+          the to attribute for the given implementation. Depends on the implementation
+          </description>
+        </field>
+        <field>
+          <name>classname</name>
+          <version>1.0.0</version>
+          <type>String</type>
+          <description>
+          Specify your own implementation of the mapper. The class has to be in the classpath of the project. 
+          Do not specify the classname if the type is used.
+          </description>
+        </field>
+      </fields>
+    </class>
+    <class>
       <name>FileItem</name>
       <version>1.0.0</version>
       <description>
@@ -274,13 +338,13 @@
         </field>
         <field>
           <name>unpack</name>
-          <type>boolean</type>
-          <defaultValue>false</defaultValue>
+          <version>1.0.0</version>
+          <association>
+            <type>Unpack</type>
+          </association>
           <description>
-            If set to true, this property will unpack all dependencies
-            into the specified output directory. When set to false
-            dependencies will be includes as archives (jars).
-            Default value is false.
+            If this property exists, this will unpack all dependencies
+            into the specified output directory.
           </description>
         </field>
         <field>
@@ -296,7 +360,40 @@
         </field>
       </fields>
     </class>
-
+    <class>
+      <name>Unpack</name>
+      <version>1.0.0</version>
+      <fields>
+        <field>
+          <name>includes</name>
+          <version>1.0.0</version>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+          <description>
+            <![CDATA[
+            When &lt;include&gt; subelements are present, they define
+            a set of files and directory to include.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>excludes</name>
+          <version>1.0.0</version>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+          <description>
+            <![CDATA[
+            When &lt;exclude&gt; subelements are present, they define
+            a set of files and directory to exclude.
+            ]]>
+          </description>
+        </field>
+      </fields>
+    </class>
   </classes>
 </model>
 
diff --git a/src/main/mdo/descriptor.mdo b/src/main/mdo/descriptor.mdo
index ce3c894..5f5870a 100644
--- a/src/main/mdo/descriptor.mdo
+++ b/src/main/mdo/descriptor.mdo
@@ -157,16 +157,23 @@
             File relative to basedir containing Component.
           </description>
         </field>
-
-
       </fields>
     </class>
-
-
     <class>
       <name>SetBase</name>
       <version>1.0.0</version>
       <fields>
+      <field>
+          <name>mapper</name>
+          <version>1.0.0</version>
+          <association>
+            <type>Mapper</type>
+          </association>
+          <defaultValue>new Mapper()</defaultValue>
+          <description>
+            Specifies the mapper used.
+          </description>
+        </field>
         <field>
           <name>outputDirectory</name>
           <version>1.0.0</version>
@@ -238,6 +245,59 @@
       </fields>
     </class>
     <class>
+      <name>Mapper</name>
+      <version>1.0.0</version>
+      <fields>
+        <field>
+          <name>type</name>
+          <version>1.0.0</version>
+          <type>String</type>
+          <defaultValue>identity</defaultValue>
+          <description>
+            specifies one of the built-in mapper implementations. A custom mapper may be specified by using the classname property.
+            If classname is being used, then the type should not be used.
+            <![CDATA[ 
+            Valid values:
+            <ul>
+              <li><b>"flatten"</b> - The target file name is identical to the source file name, with all leading directory information stripped off. Both to and from will be ignored </li>
+              <li><b>"glob"</b> - Both to and from define patterns that may contain at most one *. For each source file that matches the from pattern, a target file name will be constructed from the to pattern by substituting the * in the to pattern with the text that matches the * in the from pattern. Source file names that don't match the from pattern will be ignored/li>
+              <li><b>"regexp"</b> - Both to and from define regular expressions. If the source file name matches the from pattern, the target file name will be constructed from the to pattern, using \0 to \9 as back-references for the full match (\0) or the matches of the subexpressions in parentheses. Source files not matching the from pattern will be ignored.</li>
+              <li><b>"merge"</b> - The target file name will always be the same, as defined by to. from will be ignored</li>
+              <li><b>"package"</b> - Sharing the same syntax as the glob mapper, the package mapper replaces directory separators found in the matched source pattern with dots in the target pattern placeholder. This mapper is particularly useful in combination with <uptodate> and <junit> output. </li>
+              <li><b>"unpackage"</b> - This mapper is the inverse of the package mapper. It replaces the dots in a package name with directory separators. This is useful for matching XML formatter results against their JUnit test test cases. The mapper shares the sample syntax as the glob mapper. </li>
+            </ul>
+            ]]>
+          </description>
+          <required>true</required>
+        </field>
+        <field>
+          <name>from</name>
+          <version>1.0.0</version>
+          <type>String</type>
+          <description>
+          the from attribute for the given implementation. Depends on the implementation
+          </description>
+        </field>
+        <field>
+          <name>to</name>
+          <version>1.0.0</version>
+          <type>String</type>
+          <description>
+          the to attribute for the given implementation. Depends on the implementation
+          </description>
+        </field>
+        <field>
+          <name>classname</name>
+          <version>1.0.0</version>
+          <type>String</type>
+          <description>
+          Specify your own implementation of the mapper. The class has to be in the classpath of the project. 
+          Do not specify the classname if the type is used.
+          </description>
+        </field>
+      </fields>
+    </class>
+    <class>
       <name>FileSet</name>
       <version>1.0.0</version>
       <superClass>SetBase</superClass>
@@ -373,13 +433,13 @@
         </field>
         <field>
           <name>unpack</name>
-          <type>boolean</type>
-          <defaultValue>false</defaultValue>
+          <version>1.0.0</version>
+          <association>
+            <type>Unpack</type>
+          </association>
           <description>
-            If set to true, this property will unpack all dependencies
-            into the specified output directory. When set to false
-            dependencies will be includes as archives (jars).
-            Default value is false.
+            If this property exists, this will unpack all dependencies
+            into the specified output directory. 
           </description>
         </field>
         <field>
@@ -479,13 +539,13 @@
         </field>
         <field>
           <name>unpack</name>
-          <type>boolean</type>
-          <defaultValue>true</defaultValue>
+          <version>1.0.0</version>
+          <association>
+            <type>Unpack</type>
+          </association>
           <description>
-            If set to true, this property will unpack all module packages
-            into the specified output directory. When set to false
-            module packages will be included as archives (jars).
-            Default value is true.
+            If this property exists, this will unpack all dependencies
+            into the specified output directory. 
           </description>
         </field>
         <field>
@@ -558,6 +618,40 @@
         </field>
       </fields>
     </class>
+    <class>
+      <name>Unpack</name>
+      <version>1.0.0</version>
+      <fields>
+        <field>
+          <name>includes</name>
+          <version>1.0.0</version>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+          <description>
+            <![CDATA[
+            When &lt;include&gt; subelements are present, they define
+            a set of files and directory to include.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>excludes</name>
+          <version>1.0.0</version>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+          <description>
+            <![CDATA[
+            When &lt;exclude&gt; subelements are present, they define
+            a set of files and directory to exclude.
+            ]]>
+          </description>
+        </field>
+      </fields>
+    </class>
   </classes>
 </model>
 
diff --git a/src/test/java/org/apache/maven/plugin/assembly/DirectoryInlineMojoTest.java b/src/test/java/org/apache/maven/plugin/assembly/DirectoryInlineMojoTest.java
index 43037ef..397f5a0 100644
--- a/src/test/java/org/apache/maven/plugin/assembly/DirectoryInlineMojoTest.java
+++ b/src/test/java/org/apache/maven/plugin/assembly/DirectoryInlineMojoTest.java
@@ -1,14 +1,19 @@
 package org.apache.maven.plugin.assembly;
 
-import org.apache.maven.plugin.assembly.stubs.ArchiverManagerStub;
-import org.apache.maven.plugin.testing.AbstractMojoTestCase;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.artifact.Artifact;
-
 import java.io.File;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
-import java.util.Iterator;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.model.Model;
+import org.apache.maven.plugin.assembly.stubs.ArchiverManagerStub;
+import org.apache.maven.plugin.assembly.stubs.CountingArchiver;
+import org.apache.maven.plugin.testing.AbstractMojoTestCase;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.archiver.manager.ArchiverManager;
+import org.codehaus.plexus.util.FileUtils;
+import org.easymock.MockControl;
 
 /*
  * Copyright 2001-2006 The Apache Software Foundation.
@@ -27,25 +32,83 @@
  */
 
 public class DirectoryInlineMojoTest
-extends AbstractMojoTestCase
+    extends AbstractMojoTestCase
 {
+    private MockManager mockManager = new MockManager();
+
+    private MockControl archiverManagerControl;
+
+    private ArchiverManager archiverManager;
+
+    public void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        archiverManagerControl = MockControl.createControl( ArchiverManager.class );
+        mockManager.add( archiverManagerControl );
+
+        archiverManager = (ArchiverManager) archiverManagerControl.getMock();
+    }
+
+    public void tearDown()
+        throws Exception
+    {
+        super.tearDown();
+
+        TestUtils.cleanUp();
+    }
+
     public void testAssemblyDirectory()
         throws Exception
     {
-        File testPom = new File( getBasedir(),
-                                 "src/test/plugin-configs/directory-inline/min-plugin-config.xml" );
+        File basedir = TestUtils.createTempBasedir();
 
-        DirectoryInlineMojo mojo = ( DirectoryInlineMojo ) lookupMojo( "directory-inline", testPom );
+        // prepare the dir structure...
+        File fileSource = new File( basedir, "target/test-harness/assembly/min/target" );
+        fileSource.mkdirs();
+        
+        File sourceJar = TestUtils.findFileForClasspathResource( "test-fodder/assembly.jar" );
+        FileUtils.copyFile( sourceJar, new File( fileSource, "assembly.jar" ) );
+        
+        DirectoryMojo mojo = new DirectoryMojo();
 
-        assertNotNull( mojo );
+        File descriptor = TestUtils.findFileForClasspathResource( "assemblies/simple.xml" );
+
+        mojo.setDescriptor( descriptor );
+
+        mojo.setBasedir( basedir );
+        mojo.setFinalName( "directory-inline-min" );
+        mojo.setAppendAssemblyId( true );
+
+        Model model = new Model();
+
+        model.setGroupId( "directory-inline-tests" );
+        model.setArtifactId( "min" );
+        model.setVersion( "1.0" );
+
+        File outputDir = new File( basedir, "target/test-harness/directory-inline/min/target" );
+
+        mojo.setOutputDirectory( outputDir );
+
+        MavenProject project = new MavenProject( model );
+
+        mojo.setProject( project );
+
+        CountingArchiver archiver = new CountingArchiver();
+
+        archiverManager.getArchiver( "dir" );
+        archiverManagerControl.setReturnValue( archiver );
+
+        mojo.setArchiverManager( archiverManager );
+
+        mockManager.replayAll();
 
         mojo.execute();
 
-        Map filesArchived = ArchiverManagerStub.archiverStub.getFiles();
+        assertEquals( 1, archiver.getFileCount() );
 
-        Set files = filesArchived.keySet();
-
-        assertEquals( 1, files.size() );
+        mockManager.verifyAll();
     }
 
     public void testDependencySet()
@@ -54,11 +117,11 @@
         File testPom = new File( getBasedir(),
                                  "src/test/plugin-configs/directory-inline/dependency-set-plugin-config.xml" );
 
-        DirectoryInlineMojo mojo = ( DirectoryInlineMojo ) lookupMojo( "directory-inline", testPom );
+        DirectoryInlineMojo mojo = (DirectoryInlineMojo) lookupMojo( "directory-inline", testPom );
 
         assertNotNull( mojo );
 
-        MavenProject project = ( MavenProject ) getVariableValueFromObject( mojo, "project" );
+        MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );
 
         Set artifacts = project.getArtifacts();
 
@@ -68,9 +131,9 @@
 
         Set files = filesArchived.keySet();
 
-        for( Iterator iter = artifacts.iterator(); iter.hasNext(); )
+        for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
         {
-            Artifact artifact = ( Artifact ) iter.next();
+            Artifact artifact = (Artifact) iter.next();
 
             assertTrue( files.contains( artifact.getFile() ) );
             assertTrue( artifact.getFile().getName().endsWith( ".jar" ) );
diff --git a/src/test/java/org/apache/maven/plugin/assembly/DirectoryMojoTest.java b/src/test/java/org/apache/maven/plugin/assembly/DirectoryMojoTest.java
index f504d7d..9b54fc1 100644
--- a/src/test/java/org/apache/maven/plugin/assembly/DirectoryMojoTest.java
+++ b/src/test/java/org/apache/maven/plugin/assembly/DirectoryMojoTest.java
@@ -16,15 +16,22 @@
  * limitations under the License.
  */
 
-import org.apache.maven.plugin.assembly.stubs.ArchiverManagerStub;
-import org.apache.maven.plugin.testing.AbstractMojoTestCase;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.artifact.Artifact;
-
 import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
-import java.util.Iterator;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.model.Model;
+import org.apache.maven.plugin.assembly.stubs.ArchiverManagerStub;
+import org.apache.maven.plugin.assembly.stubs.CountingArchiver;
+import org.apache.maven.plugin.testing.AbstractMojoTestCase;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.archiver.Archiver;
+import org.codehaus.plexus.archiver.ArchiverException;
+import org.codehaus.plexus.archiver.manager.ArchiverManager;
+import org.easymock.MockControl;
 
 /**
  * @author Allan Q. Ramirez
@@ -32,6 +39,29 @@
 public class DirectoryMojoTest
     extends AbstractMojoTestCase
 {
+    private MockManager mockManager = new MockManager();
+    
+    private MockControl archiverManagerControl;
+    
+    private ArchiverManager archiverManager;
+    
+    public void setUp() throws Exception
+    {
+        super.setUp();
+        
+        archiverManagerControl = MockControl.createControl( ArchiverManager.class );
+        mockManager.add( archiverManagerControl );
+        
+        archiverManager = (ArchiverManager) archiverManagerControl.getMock();
+    }
+    
+    public void tearDown() throws Exception
+    {
+        super.tearDown();
+        
+        TestUtils.cleanUp();
+    }
+
     public void testEnvironment()
         throws Exception
     {
@@ -46,22 +76,55 @@
     public void testAssemblyDirectory()
         throws Exception
     {
-        File testPom = new File( getBasedir(),
-                                 "src/test/plugin-configs/directory/min-plugin-config.xml" );
+        // I'm assuming this test is meant to simply verify the bare-bones
+        // behavior of the directory mojo...
+        
+//        File testPom = new File( getBasedir(),
+//                                 "src/test/plugin-configs/directory/min-plugin-config.xml" );
 
-        DirectoryMojo mojo = ( DirectoryMojo ) lookupMojo( "directory", testPom );
+        DirectoryMojo mojo = new DirectoryMojo();
+        
+        File descriptor = TestUtils.findFileForClasspathResource( "assemblies/fileSet.xml" );
+        
+        mojo.setDescriptor( descriptor );
+        
+        File basedir = TestUtils.createTempBasedir();
+        
+        mojo.setBasedir( basedir );
+        mojo.setFinalName( "directory-min" );
+        mojo.setAppendAssemblyId( true );
+        
+        Model model = new Model();
+        
+        model.setGroupId( "directory-tests" );
+        model.setArtifactId( "min" );
+        model.setVersion( "1.0" );
+        
+        File outputDir = new File( basedir, "target/test-harness/directory/min/target" );
+        
+        mojo.setOutputDirectory( outputDir );
+        
+        MavenProject project = new MavenProject( model );
+        
+        mojo.setProject( project );
+        mojo.setExecutedProject( project );
+        
+        CountingArchiver archiver = new CountingArchiver();
+        
+        archiverManager.getArchiver( "dir" );
+        archiverManagerControl.setReturnValue( archiver );
+        
+        mojo.setArchiverManager( archiverManager );
 
-        assertNotNull( mojo );
-
-        AssemblyMojoTest.generateTestFileSets(getBasedir(), "\n");
+        AssemblyMojoTest.generateTestFileSets(basedir.getAbsolutePath(), "\n");
+        
+        mockManager.replayAll();
         
         mojo.execute();
 
-        Map filesArchived = ArchiverManagerStub.archiverStub.getFiles();
-
-        Set files = filesArchived.keySet();
-
-        assertEquals( 1, files.size() );
+        assertEquals( 4, archiver.getFileCount() );
+        
+        mockManager.verifyAll();
     }
 
     public void testAssemblyDirectoryWithAppendAssemblyIdAsFalse()
@@ -157,4 +220,5 @@
             //expected
         }
     }
+    
 }
diff --git a/src/test/java/org/apache/maven/plugin/assembly/MockManager.java b/src/test/java/org/apache/maven/plugin/assembly/MockManager.java
new file mode 100644
index 0000000..ccc2ccc
--- /dev/null
+++ b/src/test/java/org/apache/maven/plugin/assembly/MockManager.java
@@ -0,0 +1,39 @@
+package org.apache.maven.plugin.assembly;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.easymock.MockControl;
+
+public class MockManager
+{
+    
+    private List mockControls = new ArrayList();
+    
+    public void add( MockControl control )
+    {
+        mockControls.add( control );
+    }
+    
+    public void replayAll()
+    {
+        for ( Iterator it = mockControls.iterator(); it.hasNext(); )
+        {
+            MockControl control = (MockControl) it.next();
+            
+            control.replay();
+        }
+    }
+    
+    public void verifyAll()
+    {
+        for ( Iterator it = mockControls.iterator(); it.hasNext(); )
+        {
+            MockControl control = (MockControl) it.next();
+            
+            control.verify();
+        }
+    }
+
+}
diff --git a/src/test/java/org/apache/maven/plugin/assembly/TestUtils.java b/src/test/java/org/apache/maven/plugin/assembly/TestUtils.java
new file mode 100644
index 0000000..451051c
--- /dev/null
+++ b/src/test/java/org/apache/maven/plugin/assembly/TestUtils.java
@@ -0,0 +1,68 @@
+package org.apache.maven.plugin.assembly;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.codehaus.plexus.util.FileUtils;
+
+public class TestUtils
+{
+    
+    private static Set toDelete = new HashSet();
+    
+    public static void cleanUp() throws IOException
+    {
+        
+        for ( Iterator it = toDelete.iterator(); it.hasNext(); )
+        {
+            File file = (File) it.next();
+            
+            if ( file.exists() )
+            {
+                if ( file.isDirectory() )
+                {
+                    FileUtils.deleteDirectory( file );
+                }
+                else
+                {
+                    file.delete();
+                }
+            }
+        }
+    }
+    
+    public static void markForDeletion( File file )
+    {
+        toDelete.add( file );
+    }
+
+    public static File createTempBasedir() throws InterruptedException
+    {
+        Thread.sleep( 100 );
+        
+        File basedir = new File( System.getProperty( "java.io.tmpdir" ), "basedir." + System.currentTimeMillis() );
+        
+        toDelete.add( basedir );
+        
+        return basedir;
+    }
+
+    public static File findFileForClasspathResource( String resourceName )
+    {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        
+        URL resource = cl.getResource( resourceName );
+        
+        if ( resource != null )
+        {
+            return new File( resource.getPath() );
+        }
+
+        return null;
+    }
+
+}
diff --git a/src/test/java/org/apache/maven/plugin/assembly/stubs/CountingArchiver.java b/src/test/java/org/apache/maven/plugin/assembly/stubs/CountingArchiver.java
new file mode 100644
index 0000000..db025a7
--- /dev/null
+++ b/src/test/java/org/apache/maven/plugin/assembly/stubs/CountingArchiver.java
@@ -0,0 +1,115 @@
+package org.apache.maven.plugin.assembly.stubs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+import org.codehaus.plexus.archiver.Archiver;
+import org.codehaus.plexus.archiver.ArchiverException;
+
+public class CountingArchiver implements Archiver
+{
+    
+    private int dirsAdded = 0;
+    private int filesAdded = 0;
+    private File destFile;
+
+    public void addDirectory( File arg0 )
+        throws ArchiverException
+    {
+        dirsAdded++;
+    }
+
+    public int getFileCount()
+    {
+        return filesAdded;
+    }
+    
+    public int getDirCount()
+    {
+        return dirsAdded;
+    }
+
+    public void addDirectory( File arg0, String arg1 )
+        throws ArchiverException
+    {
+        System.out.println( "Adding dir: " + arg0 );
+        dirsAdded++;
+    }
+
+    public void addDirectory( File arg0, String[] arg1, String[] arg2 )
+        throws ArchiverException
+    {
+        System.out.println( "Adding dir: " + arg0 );
+        dirsAdded++;
+    }
+
+    public void addDirectory( File arg0, String arg1, String[] arg2, String[] arg3 )
+        throws ArchiverException
+    {
+        System.out.println( "Adding dir: " + arg0 );
+        dirsAdded++;
+    }
+
+    public void addFile( File arg0, String arg1 )
+        throws ArchiverException
+    {
+        System.out.println( "Adding file: " + arg0 );
+        filesAdded++;
+    }
+
+    public void addFile( File arg0, String arg1, int arg2 )
+        throws ArchiverException
+    {
+        System.out.println( "Adding file: " + arg0 );
+        filesAdded++;
+    }
+
+    public void createArchive()
+        throws ArchiverException, IOException
+    {
+    }
+
+    public int getDefaultDirectoryMode()
+    {
+        return 0;
+    }
+
+    public int getDefaultFileMode()
+    {
+        return 0;
+    }
+
+    public File getDestFile()
+    {
+        return destFile;
+    }
+
+    public Map getFiles()
+    {
+        return null;
+    }
+
+    public boolean getIncludeEmptyDirs()
+    {
+        return false;
+    }
+
+    public void setDefaultDirectoryMode( int arg0 )
+    {
+    }
+
+    public void setDefaultFileMode( int arg0 )
+    {
+    }
+
+    public void setDestFile( File arg0 )
+    {
+        this.destFile = arg0;
+    }
+
+    public void setIncludeEmptyDirs( boolean arg0 )
+    {
+    }
+    
+}
diff --git a/src/test/resources/assemblies/components/dependencySet.xml b/src/test/resources/assemblies/components/dependencySet.xml
index ecfcb49..385a4e3 100644
--- a/src/test/resources/assemblies/components/dependencySet.xml
+++ b/src/test/resources/assemblies/components/dependencySet.xml
@@ -17,7 +17,6 @@
 <component>
   <dependencySets>
     <dependencySet>
-      <unpack>false</unpack>
       <outputDirectory></outputDirectory>
       <scope>test</scope>
     </dependencySet>
diff --git a/src/test/resources/assemblies/dependencySet-default.xml b/src/test/resources/assemblies/dependencySet-default.xml
index 392ba53..5338838 100644
--- a/src/test/resources/assemblies/dependencySet-default.xml
+++ b/src/test/resources/assemblies/dependencySet-default.xml
@@ -21,7 +21,6 @@
   </formats>
   <dependencySets>
     <dependencySet>
-      <unpack>false</unpack>
       <outputDirectory></outputDirectory>
       <scope>test</scope>
     </dependencySet>
diff --git a/src/test/resources/assemblies/dependencySet-excludes.xml b/src/test/resources/assemblies/dependencySet-excludes.xml
index 41ded42..2b3cf62 100644
--- a/src/test/resources/assemblies/dependencySet-excludes.xml
+++ b/src/test/resources/assemblies/dependencySet-excludes.xml
@@ -21,7 +21,6 @@
   </formats>
   <dependencySets>
     <dependencySet>
-      <unpack>false</unpack>
       <outputDirectory></outputDirectory>
       <scope>test</scope>
       <excludes>
diff --git a/src/test/resources/assemblies/dependencySet-filename-mapping-and-classifier.xml b/src/test/resources/assemblies/dependencySet-filename-mapping-and-classifier.xml
index 8f40cc1..22d0697 100644
--- a/src/test/resources/assemblies/dependencySet-filename-mapping-and-classifier.xml
+++ b/src/test/resources/assemblies/dependencySet-filename-mapping-and-classifier.xml
@@ -23,7 +23,6 @@
   <dependencySets>
     <dependencySet>
       <outputFileNameMapping>${version}.${artifactId}.${groupId}</outputFileNameMapping>
-      <unpack>false</unpack>
       <outputDirectory>libs</outputDirectory>
       <scope>test</scope>
     </dependencySet>
diff --git a/src/test/resources/assemblies/dependencySet-filename-mapping.xml b/src/test/resources/assemblies/dependencySet-filename-mapping.xml
index 518fbd4..6bcf196 100644
--- a/src/test/resources/assemblies/dependencySet-filename-mapping.xml
+++ b/src/test/resources/assemblies/dependencySet-filename-mapping.xml
@@ -23,7 +23,6 @@
   <dependencySets>
     <dependencySet>
       <outputFileNameMapping>${version}-${artifactId}-${groupId}</outputFileNameMapping>
-      <unpack>false</unpack>
       <outputDirectory>libs</outputDirectory>
       <scope>test</scope>
     </dependencySet>
diff --git a/src/test/resources/assemblies/dependencySet-includes.xml b/src/test/resources/assemblies/dependencySet-includes.xml
index 78a2b1d..8f6ab18 100644
--- a/src/test/resources/assemblies/dependencySet-includes.xml
+++ b/src/test/resources/assemblies/dependencySet-includes.xml
@@ -21,7 +21,6 @@
   </formats>
   <dependencySets>
     <dependencySet>
-      <unpack>false</unpack>
       <outputDirectory></outputDirectory>
       <scope>test</scope>
       <includes>
diff --git a/src/test/resources/assemblies/dependencySet-scoped.xml b/src/test/resources/assemblies/dependencySet-scoped.xml
index c5f5f5f..350829e 100644
--- a/src/test/resources/assemblies/dependencySet-scoped.xml
+++ b/src/test/resources/assemblies/dependencySet-scoped.xml
@@ -21,7 +21,6 @@
   </formats>
   <dependencySets>
     <dependencySet>
-      <unpack>false</unpack>
       <outputDirectory></outputDirectory>
     </dependencySet>
   </dependencySets>
diff --git a/src/test/resources/assemblies/dependencySet-unpack.xml b/src/test/resources/assemblies/dependencySet-unpack.xml
index f642710..1255d0b 100644
--- a/src/test/resources/assemblies/dependencySet-unpack.xml
+++ b/src/test/resources/assemblies/dependencySet-unpack.xml
@@ -21,7 +21,7 @@
   </formats>
   <dependencySets>
     <dependencySet>
-      <unpack>true</unpack>
+      <unpack/>
       <outputDirectory></outputDirectory>
       <scope>test</scope>
     </dependencySet>
diff --git a/src/test/resources/assemblies/moduleSet-packed-including-dependencies.xml b/src/test/resources/assemblies/moduleSet-packed-including-dependencies.xml
index c3ed9af..31b3592 100644
--- a/src/test/resources/assemblies/moduleSet-packed-including-dependencies.xml
+++ b/src/test/resources/assemblies/moduleSet-packed-including-dependencies.xml
@@ -22,7 +22,6 @@
   <moduleSets>
     <moduleSet>
       <binaries>
-        <unpack>false</unpack>
         <includeDependencies>true</includeDependencies>
       </binaries>
     </moduleSet>
diff --git a/src/test/resources/assemblies/moduleSet-packed.xml b/src/test/resources/assemblies/moduleSet-packed.xml
index 3a06379..818c155 100644
--- a/src/test/resources/assemblies/moduleSet-packed.xml
+++ b/src/test/resources/assemblies/moduleSet-packed.xml
@@ -21,9 +21,7 @@
   </formats>
   <moduleSets>
     <moduleSet>
-      <binaries>
-        <unpack>false</unpack>
-      </binaries>
+      <binaries/>
     </moduleSet>
   </moduleSets>
 </assembly>
diff --git a/src/test/resources/test-fodder/assembly.jar b/src/test/resources/test-fodder/assembly.jar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/test/resources/test-fodder/assembly.jar