Coverage Report - org.apache.maven.plugin.war.packaging.AbstractWarPackagingTask
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractWarPackagingTask
73%
47/64
81%
21/26
2,385
AbstractWarPackagingTask$1
100%
13/13
N/A
2,385
 
 1  
 package org.apache.maven.plugin.war.packaging;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.File;
 23  
 import java.io.IOException;
 24  
 import java.util.Iterator;
 25  
 
 26  
 import org.apache.maven.artifact.Artifact;
 27  
 import org.apache.maven.plugin.MojoExecutionException;
 28  
 import org.apache.maven.plugin.war.AbstractWarMojo;
 29  
 import org.apache.maven.plugin.war.util.MappingUtils;
 30  
 import org.apache.maven.plugin.war.util.PathSet;
 31  
 import org.apache.maven.plugin.war.util.WebappStructure;
 32  
 import org.apache.maven.shared.filtering.MavenFilteringException;
 33  
 import org.codehaus.plexus.archiver.ArchiverException;
 34  
 import org.codehaus.plexus.archiver.UnArchiver;
 35  
 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
 36  
 import org.codehaus.plexus.interpolation.InterpolationException;
 37  
 import org.codehaus.plexus.util.DirectoryScanner;
 38  
 import org.codehaus.plexus.util.FileUtils;
 39  
 
 40  
 /**
 41  
  * @author Stephane Nicoll
 42  
  * @version $Id: AbstractWarPackagingTask.java 985593 2010-08-14 22:12:09Z dennisl $
 43  
  */
 44  226
 public abstract class AbstractWarPackagingTask
 45  
     implements WarPackagingTask
 46  
 {
 47  1
     public static final String[] DEFAULT_INCLUDES = {"**/**"};
 48  
 
 49  
     public static final String WEB_INF_PATH = "WEB-INF";
 50  
 
 51  
     public static final String META_INF_PATH = "META-INF";
 52  
 
 53  
     public static final String CLASSES_PATH = "WEB-INF/classes/";
 54  
 
 55  
     public static final String LIB_PATH = "WEB-INF/lib/";
 56  
 
 57  
     /**
 58  
      * Copies the files if possible with an optional target prefix.
 59  
      * <p/>
 60  
      * Copy uses a first-win strategy: files that have already been copied by previous
 61  
      * tasks are ignored. This method makes sure to update the list of protected files
 62  
      * which gives the list of files that have already been copied.
 63  
      * <p/>
 64  
      * If the structure of the source directory is not the same as the root of the
 65  
      * webapp, use the <tt>targetPrefix</tt> parameter to specify in which particular
 66  
      * directory the files should be copied. Use <tt>null</tt> to copy the files with
 67  
      * the same structure
 68  
      *
 69  
      * @param sourceId       the source id
 70  
      * @param context        the context to use
 71  
      * @param sourceBaseDir  the base directory from which the <tt>sourceFilesSet</tt> will be copied
 72  
      * @param sourceFilesSet the files to be copied
 73  
      * @param targetPrefix   the prefix to add to the target file name
 74  
      * @throws IOException if an error occurred while copying the files
 75  
      */
 76  
     protected void copyFiles( String sourceId, WarPackagingContext context, File sourceBaseDir, PathSet sourceFilesSet,
 77  
                               String targetPrefix, boolean filtered )
 78  
         throws IOException, MojoExecutionException
 79  
     {
 80  152
         for ( Iterator iter = sourceFilesSet.iterator(); iter.hasNext(); )
 81  
         {
 82  334
             final String fileToCopyName = (String) iter.next();
 83  334
             final File sourceFile = new File( sourceBaseDir, fileToCopyName );
 84  
 
 85  
             String destinationFileName;
 86  334
             if ( targetPrefix == null )
 87  
             {
 88  323
                 destinationFileName = fileToCopyName;
 89  
             }
 90  
             else
 91  
             {
 92  11
                 destinationFileName = targetPrefix + fileToCopyName;
 93  
             }
 94  
             
 95  
 
 96  334
             if ( filtered
 97  
                 && !context.isNonFilteredExtension( sourceFile.getName() ) ) 
 98  
             {
 99  0
                 copyFilteredFile( sourceId, context, sourceFile, destinationFileName );
 100  
             }
 101  
             else
 102  
             {
 103  334
                 copyFile( sourceId, context, sourceFile, destinationFileName );
 104  
             }
 105  334
         }
 106  152
     }
 107  
 
 108  
     /**
 109  
      * Copies the files if possible as is.
 110  
      * <p/>
 111  
      * Copy uses a first-win strategy: files that have already been copied by previous
 112  
      * tasks are ignored. This method makes sure to update the list of protected files
 113  
      * which gives the list of files that have already been copied.
 114  
      *
 115  
      * @param sourceId       the source id
 116  
      * @param context        the context to use
 117  
      * @param sourceBaseDir  the base directory from which the <tt>sourceFilesSet</tt> will be copied
 118  
      * @param sourceFilesSet the files to be copied
 119  
      * @throws IOException if an error occurred while copying the files
 120  
      */
 121  
     protected void copyFiles( String sourceId, WarPackagingContext context, File sourceBaseDir, PathSet sourceFilesSet,
 122  
                               boolean filtered )
 123  
         throws IOException, MojoExecutionException
 124  
     {
 125  91
         copyFiles( sourceId, context, sourceBaseDir, sourceFilesSet, null, filtered );
 126  91
     }
 127  
 
 128  
     /**
 129  
      * Copy the specified file if the target location has not yet already been used.
 130  
      * <p/>
 131  
      * The <tt>targetFileName</tt> is the relative path according to the root of
 132  
      * the generated web application.
 133  
      *
 134  
      * @param sourceId       the source id
 135  
      * @param context        the context to use
 136  
      * @param file           the file to copy
 137  
      * @param targetFilename the relative path according to the root of the webapp
 138  
      * @throws IOException if an error occurred while copying
 139  
      */
 140  
     protected void copyFile( String sourceId, final WarPackagingContext context, final File file,
 141  
                              String targetFilename )
 142  
         throws IOException
 143  
     {
 144  357
         final File targetFile = new File( context.getWebappDirectory(), targetFilename );
 145  357
         context.getWebappStructure().registerFile( sourceId, targetFilename, new WebappStructure.RegistrationCallback()
 146  
         {
 147  
             public void registered( String ownerId, String targetFilename )
 148  
                 throws IOException
 149  
             {
 150  211
                 copyFile( context, file, targetFile, targetFilename, false );
 151  211
             }
 152  
 
 153  
             public void alreadyRegistered( String ownerId, String targetFilename )
 154  
                 throws IOException
 155  
             {
 156  23
                 copyFile( context, file, targetFile, targetFilename, true );
 157  23
             }
 158  
 
 159  
             public void refused( String ownerId, String targetFilename, String actualOwnerId )
 160  
                 throws IOException
 161  
             {
 162  115
                 context.getLog().debug( " - " + targetFilename + " wasn't copied because it has "
 163  
                     + "already been packaged for overlay [" + actualOwnerId + "]." );
 164  115
             }
 165  
 
 166  
             public void superseded( String ownerId, String targetFilename, String deprecatedOwnerId )
 167  
                 throws IOException
 168  
             {
 169  6
                 context.getLog().info( "File [" + targetFilename + "] belonged to overlay [" + deprecatedOwnerId
 170  
                     + "] so it will be overwritten." );
 171  6
                 copyFile( context, file, targetFile, targetFilename, false );
 172  6
             }
 173  
 
 174  357
             public void supersededUnknownOwner( String ownerId, String targetFilename, String unknownOwnerId )
 175  
                 throws IOException
 176  
             {
 177  2
                 context.getLog()
 178  
                     .warn( "File [" + targetFilename + "] belonged to overlay [" + unknownOwnerId
 179  
                         + "] which does not exist anymore in the current project. It is recommended to invoke "
 180  
                         + "clean if the dependencies of the project changed." );
 181  2
                 copyFile( context, file, targetFile, targetFilename, false );
 182  2
             }
 183  
         } );
 184  357
     }
 185  
 
 186  
     /**
 187  
      * Copy the specified file if the target location has not yet already been
 188  
      * used and filter its content with the configured filter properties.
 189  
      * <p/>
 190  
      * The <tt>targetFileName</tt> is the relative path according to the root of
 191  
      * the generated web application.
 192  
      *
 193  
      * @param sourceId       the source id
 194  
      * @param context        the context to use
 195  
      * @param file           the file to copy
 196  
      * @param targetFilename the relative path according to the root of the webapp
 197  
      * @return true if the file has been copied, false otherwise
 198  
      * @throws IOException            if an error occurred while copying
 199  
      * @throws MojoExecutionException if an error occurred while retrieving the filter properties
 200  
      */
 201  
     protected boolean copyFilteredFile( String sourceId, final WarPackagingContext context, File file,
 202  
                                         String targetFilename )
 203  
         throws IOException, MojoExecutionException
 204  
     {
 205  
 
 206  6
         if ( context.getWebappStructure().registerFile( sourceId, targetFilename ) )
 207  
         {
 208  6
             final File targetFile = new File( context.getWebappDirectory(), targetFilename );
 209  
             try
 210  
             {
 211  
                 // fix for MWAR-36, ensures that the parent dir are created first
 212  6
                 targetFile.getParentFile().mkdirs();
 213  
                 // TODO: add encoding support (null mean platform encoding)
 214  6
                 context.getMavenFileFilter().copyFile( file, targetFile, true, context.getFilterWrappers(), null );
 215  
             }
 216  0
             catch ( MavenFilteringException e )
 217  
             {
 218  0
                 throw new MojoExecutionException( e.getMessage(), e );
 219  6
             }
 220  
             // Add the file to the protected list
 221  6
             context.getLog().debug( " + " + targetFilename + " has been copied (filtered)." );
 222  6
             return true;
 223  
         }
 224  
         else
 225  
         {
 226  0
             context.getLog().debug(
 227  
                 " - " + targetFilename + " wasn't copied because it has already been packaged (filtered)." );
 228  0
             return false;
 229  
         }
 230  
     }
 231  
 
 232  
 
 233  
     /**
 234  
      * Unpacks the specified file to the specified directory.
 235  
      *
 236  
      * @param context         the packaging context
 237  
      * @param file            the file to unpack
 238  
      * @param unpackDirectory the directory to use for th unpacked file
 239  
      * @throws MojoExecutionException if an error occurred while unpacking the file
 240  
      */
 241  
     protected void doUnpack( WarPackagingContext context, File file, File unpackDirectory )
 242  
         throws MojoExecutionException
 243  
     {
 244  0
         String archiveExt = FileUtils.getExtension( file.getAbsolutePath() ).toLowerCase();
 245  
 
 246  
         try
 247  
         {
 248  0
             UnArchiver unArchiver = context.getArchiverManager().getUnArchiver( archiveExt );
 249  0
             unArchiver.setSourceFile( file );
 250  0
             unArchiver.setDestDirectory( unpackDirectory );
 251  0
             unArchiver.setOverwrite( true );
 252  0
             unArchiver.extract();
 253  
         }
 254  0
         catch ( ArchiverException e )
 255  
         {
 256  0
             throw new MojoExecutionException( "Error unpacking file [" + file.getAbsolutePath() + "]" + "to ["
 257  
                 + unpackDirectory.getAbsolutePath() + "]", e );
 258  
         }
 259  0
         catch ( NoSuchArchiverException e )
 260  
         {
 261  0
             context.getLog().warn( "Skip unpacking dependency file [" + file.getAbsolutePath()
 262  
                 + " with unknown extension [" + archiveExt + "]" );
 263  0
         }
 264  0
     }
 265  
 
 266  
     /**
 267  
      * Copy file from source to destination. The directories up to <code>destination</code>
 268  
      * will be created if they don't already exist. if the <code>onlyIfModified</code> flag
 269  
      * is <tt>false</tt>, <code>destination</code> will be overwritten if it already exists. If the
 270  
      * flag is <tt>true</tt> destination will be overwritten if it's not up to date.
 271  
      * <p/>
 272  
      *
 273  
      * @param context        the packaging context
 274  
      * @param source         an existing non-directory <code>File</code> to copy bytes from
 275  
      * @param destination    a non-directory <code>File</code> to write bytes to (possibly overwriting).
 276  
      * @param targetFilename the relative path of the file from the webapp root directory
 277  
      * @param onlyIfModified if true, copy the file only if the source has changed, always copy otherwise
 278  
      * @return true if the file has been copied/updated, false otherwise
 279  
      * @throws IOException if <code>source</code> does not exist, <code>destination</code> cannot
 280  
      *                     be written to, or an IO error occurs during copying
 281  
      */
 282  
     protected boolean copyFile( WarPackagingContext context, File source, File destination, String targetFilename,
 283  
                                 boolean onlyIfModified )
 284  
         throws IOException
 285  
     {
 286  266
         if ( onlyIfModified && destination.lastModified() >= source.lastModified() )
 287  
         {
 288  12
             context.getLog().debug( " * " + targetFilename + " is up to date." );
 289  12
             return false;
 290  
         }
 291  
         else
 292  
         {
 293  254
             FileUtils.copyFile( source.getCanonicalFile(), destination );
 294  
             // preserve timestamp
 295  254
             destination.setLastModified( source.lastModified() );
 296  254
             context.getLog().debug( " + " + targetFilename + " has been copied." );
 297  254
             return true;
 298  
         }
 299  
     }
 300  
 
 301  
     /**
 302  
      * Returns the file to copy. If the includes are <tt>null</tt> or empty, the
 303  
      * default includes are used.
 304  
      *
 305  
      * @param baseDir  the base directory to start from
 306  
      * @param includes the includes
 307  
      * @param excludes the excludes
 308  
      * @return the files to copy
 309  
      */
 310  
     protected PathSet getFilesToIncludes( File baseDir, String[] includes, String[] excludes )
 311  
     {
 312  152
         final DirectoryScanner scanner = new DirectoryScanner();
 313  152
         scanner.setBasedir( baseDir );
 314  
 
 315  152
         if ( excludes != null )
 316  
         {
 317  92
             scanner.setExcludes( excludes );
 318  
         }
 319  152
         scanner.addDefaultExcludes();
 320  
 
 321  152
         if ( includes != null && includes.length > 0 )
 322  
         {
 323  34
             scanner.setIncludes( includes );
 324  
         }
 325  
         else
 326  
         {
 327  118
             scanner.setIncludes( DEFAULT_INCLUDES );
 328  
         }
 329  
 
 330  152
         scanner.scan();
 331  
 
 332  152
         return new PathSet( scanner.getIncludedFiles() );
 333  
 
 334  
     }
 335  
 
 336  
     /**
 337  
      * Returns the final name of the specified artifact.
 338  
      * <p/>
 339  
      * If the <tt>outputFileNameMapping</tt> is set, it is used, otherwise
 340  
      * the standard naming scheme is used.
 341  
      *
 342  
      * @param context  the packaging context
 343  
      * @param artifact the artifact
 344  
      * @return the converted filename of the artifact
 345  
      */
 346  
     protected String getArtifactFinalName( WarPackagingContext context, Artifact artifact )
 347  
         throws InterpolationException
 348  
     {
 349  108
         if ( context.getOutputFileNameMapping() != null )
 350  
         {
 351  6
             return MappingUtils.evaluateFileNameMapping( context.getOutputFileNameMapping(), artifact );
 352  
         }
 353  
 
 354  102
         String classifier = artifact.getClassifier();
 355  102
         if ( ( classifier != null ) && !( "".equals( classifier.trim() ) ) )
 356  
         {
 357  4
             return MappingUtils.evaluateFileNameMapping( AbstractWarMojo.DEFAULT_FILE_NAME_MAPPING_CLASSIFIER,
 358  
                                                          artifact );
 359  
         }
 360  
         else
 361  
         {
 362  98
             return MappingUtils.evaluateFileNameMapping( AbstractWarMojo.DEFAULT_FILE_NAME_MAPPING, artifact );
 363  
         }
 364  
 
 365  
     }
 366  
 }