Coverage Report - org.codehaus.plexus.archiver.AbstractArchiver
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractArchiver
70 %
226/320
63 %
78/122
2,627
AbstractArchiver$1
64 %
35/54
77 %
28/36
2,627
AbstractArchiver$AddedResourceCollection
75 %
9/12
100 %
6/6
2,627
 
 1  0
 /**
 2  
  *
 3  
  * Copyright 2004 The Apache Software Foundation
 4  
  *
 5  
  * Licensed under the Apache License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  * http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.codehaus.plexus.archiver;
 18  
 
 19  
 import java.io.Closeable;
 20  
 import java.io.File;
 21  
 import java.io.IOException;
 22  
 import java.lang.reflect.UndeclaredThrowableException;
 23  
 import java.nio.charset.Charset;
 24  
 import java.util.ArrayList;
 25  
 import java.util.HashMap;
 26  
 import java.util.HashSet;
 27  
 import java.util.Iterator;
 28  
 import java.util.List;
 29  
 import java.util.Map;
 30  
 import java.util.NoSuchElementException;
 31  
 import java.util.Set;
 32  
 import javax.annotation.Nonnull;
 33  
 import org.codehaus.plexus.PlexusConstants;
 34  
 import org.codehaus.plexus.PlexusContainer;
 35  
 import org.codehaus.plexus.archiver.manager.ArchiverManager;
 36  
 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
 37  
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 38  
 import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributes;
 39  
 import org.codehaus.plexus.components.io.functions.ResourceAttributeSupplier;
 40  
 import org.codehaus.plexus.components.io.resources.AbstractPlexusIoResourceCollection;
 41  
 import org.codehaus.plexus.components.io.resources.EncodingSupported;
 42  
 import org.codehaus.plexus.components.io.resources.PlexusIoArchivedResourceCollection;
 43  
 import org.codehaus.plexus.components.io.resources.PlexusIoFileResourceCollection;
 44  
 import org.codehaus.plexus.components.io.resources.PlexusIoResource;
 45  
 import org.codehaus.plexus.components.io.resources.PlexusIoResourceCollection;
 46  
 import org.codehaus.plexus.components.io.resources.proxy.PlexusIoProxyResourceCollection;
 47  
 import org.codehaus.plexus.context.Context;
 48  
 import org.codehaus.plexus.context.ContextException;
 49  
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 50  
 import org.codehaus.plexus.logging.Logger;
 51  
 import org.codehaus.plexus.logging.console.ConsoleLogger;
 52  
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
 53  
 import org.codehaus.plexus.util.Os;
 54  
 import static org.codehaus.plexus.archiver.util.DefaultArchivedFileSet.archivedFileSet;
 55  
 import static org.codehaus.plexus.archiver.util.DefaultFileSet.fileSet;
 56  
 
 57  49808
 public abstract class AbstractArchiver
 58  
     extends AbstractLogEnabled
 59  
     implements Archiver, Contextualizable, FinalizerEnabled
 60  
 {
 61  
 
 62  
     private Logger logger;
 63  
 
 64  
     private File destFile;
 65  
 
 66  
     /**
 67  
      * A list of the following objects:
 68  
      * <ul>
 69  
      * <li>Instances of {@link ArchiveEntry}, which are passed back by {@link #getResources()} without modifications
 70  
      * .</li>
 71  
      * <li>Instances of {@link PlexusIoResourceCollection}, which are converted into an {@link Iterator} over instances
 72  
      * of {@link ArchiveEntry} by {@link #getResources()}.
 73  
      * </ul>
 74  
      */
 75  129
     private final List<Object> resources = new ArrayList<Object>();
 76  
 
 77  129
     private boolean includeEmptyDirs = true;
 78  
 
 79  129
     private int forcedFileMode = -1; // Will always be used
 80  
 
 81  129
     private int forcedDirectoryMode = -1; // Will always be used
 82  
 
 83  129
     private int defaultFileMode = -1; // Optionally used if a value is needed
 84  
 
 85  129
     private int defaultDirectoryMode = -1; // Optionally used if a value is needed
 86  
 
 87  129
     private boolean forced = true;
 88  
 
 89  
     private List<ArchiveFinalizer> finalizers;
 90  
 
 91  
     private File dotFileDirectory;
 92  
 
 93  129
     private String duplicateBehavior = Archiver.DUPLICATES_SKIP;
 94  
 
 95  
     // On lunix-like systems, we replace windows backslashes with forward slashes
 96  129
     private final boolean replacePathSlashesToJavaPaths = File.separatorChar == '/';
 97  
 
 98  129
     private final List<Closeable> closeables = new ArrayList<Closeable>();
 99  
 
 100  
     /**
 101  
      * since 2.2 is on by default
 102  
      *
 103  
      * @since 1.1
 104  
      */
 105  129
     private boolean useJvmChmod = true;
 106  
 
 107  
     // contextualized.
 108  
     private ArchiverManager archiverManager;
 109  
 
 110  148487
     private static class AddedResourceCollection
 111  
     {
 112  
 
 113  0
         private final PlexusIoResourceCollection resources;
 114  
 
 115  
         private final int forcedFileMode;
 116  
 
 117  
         private final int forcedDirectoryMode;
 118  
 
 119  0
         public AddedResourceCollection( PlexusIoResourceCollection resources, int forcedFileMode, int forcedDirMode )
 120  80
         {
 121  80
             this.resources = resources;
 122  80
             this.forcedFileMode = forcedFileMode;
 123  80
             this.forcedDirectoryMode = forcedDirMode;
 124  80
         }
 125  
 
 126  0
         private int maybeOverridden( int suggestedMode, boolean isDir )
 127  
         {
 128  49471
             if ( isDir )
 129  
             {
 130  1244
                 return forcedDirectoryMode >= 0 ? forcedDirectoryMode : suggestedMode;
 131  
             }
 132  
             else
 133  
             {
 134  48227
                 return forcedFileMode >= 0 ? forcedFileMode : suggestedMode;
 135  
 
 136  
             }
 137  
         }
 138  
 
 139  
     }
 140  
 
 141  
     /**
 142  
      * @since 1.1
 143  
      */
 144  129
     private boolean ignorePermissions = false;
 145  
 
 146  
     @Override
 147  
     public String getDuplicateBehavior()
 148  
     {
 149  0
         return duplicateBehavior;
 150  
     }
 151  
 
 152  
     @Override
 153  
     public void setDuplicateBehavior( final String duplicate )
 154  
     {
 155  2
         if ( !Archiver.DUPLICATES_VALID_BEHAVIORS.contains( duplicate ) )
 156  
         {
 157  0
             throw new IllegalArgumentException(
 158  0
                 "Invalid duplicate-file behavior: \'" + duplicate + "\'. Please specify one of: "
 159  0
                     + Archiver.DUPLICATES_VALID_BEHAVIORS );
 160  
         }
 161  
 
 162  2
         duplicateBehavior = duplicate;
 163  2
     }
 164  
 
 165  
     @Override
 166  
     public final void setFileMode( final int mode )
 167  
     {
 168  28
         if ( mode >= 0 )
 169  
         {
 170  27
             forcedFileMode = ( mode & UnixStat.PERM_MASK ) | UnixStat.FILE_FLAG;
 171  0
         }
 172  
         else
 173  
         {
 174  1
             forcedFileMode = -1;
 175  
         }
 176  28
     }
 177  
 
 178  
     @Override
 179  
     public final void setDefaultFileMode( final int mode )
 180  
     {
 181  2
         defaultFileMode = ( mode & UnixStat.PERM_MASK ) | UnixStat.FILE_FLAG;
 182  2
     }
 183  
 
 184  
     @Override
 185  
     public final int getOverrideFileMode()
 186  
     {
 187  595
         return forcedFileMode;
 188  
     }
 189  
 
 190  
     @Override
 191  
     public final int getFileMode()
 192  
     {
 193  3
         if ( forcedFileMode < 0 )
 194  
         {
 195  2
             if ( defaultFileMode < 0 )
 196  
             {
 197  1
                 return DEFAULT_FILE_MODE;
 198  
             }
 199  
 
 200  1
             return defaultFileMode;
 201  
         }
 202  
 
 203  1
         return forcedFileMode;
 204  
     }
 205  
 
 206  
     @Override
 207  
     public final int getDefaultFileMode()
 208  
     {
 209  77
         return defaultFileMode;
 210  
     }
 211  
 
 212  
     /**
 213  
      * @deprecated Use {@link Archiver#getDefaultFileMode()}.
 214  
      */
 215  
     @Deprecated
 216  
     public final int getRawDefaultFileMode()
 217  
     {
 218  0
         return getDefaultFileMode();
 219  
     }
 220  
 
 221  
     @Override
 222  
     public final void setDirectoryMode( final int mode )
 223  
     {
 224  25
         if ( mode >= 0 )
 225  
         {
 226  23
             forcedDirectoryMode = ( mode & UnixStat.PERM_MASK ) | UnixStat.DIR_FLAG;
 227  0
         }
 228  
         else
 229  
         {
 230  2
             forcedDirectoryMode = -1;
 231  
         }
 232  25
     }
 233  
 
 234  
     @Override
 235  
     public final void setDefaultDirectoryMode( final int mode )
 236  
     {
 237  6
         defaultDirectoryMode = ( mode & UnixStat.PERM_MASK ) | UnixStat.DIR_FLAG;
 238  6
     }
 239  
 
 240  
     @Override
 241  
     public final int getOverrideDirectoryMode()
 242  
     {
 243  93
         return forcedDirectoryMode;
 244  
     }
 245  
 
 246  
     @Override
 247  
     public final int getDirectoryMode()
 248  
     {
 249  49752
         if ( forcedDirectoryMode < 0 )
 250  
         {
 251  48524
             if ( defaultDirectoryMode < 0 )
 252  
             {
 253  48522
                 return DEFAULT_DIR_MODE;
 254  
             }
 255  
 
 256  2
             return defaultDirectoryMode;
 257  
         }
 258  
 
 259  1228
         return forcedDirectoryMode;
 260  
     }
 261  
 
 262  
     @Override
 263  
     public final int getDefaultDirectoryMode()
 264  
     {
 265  152
         if ( defaultDirectoryMode < 0 )
 266  
         {
 267  147
             return DEFAULT_DIR_MODE;
 268  
         }
 269  
         else
 270  
         {
 271  5
             return defaultDirectoryMode;
 272  
         }
 273  
     }
 274  
 
 275  
     @Override
 276  
     public boolean getIncludeEmptyDirs()
 277  
     {
 278  48213
         return includeEmptyDirs;
 279  
     }
 280  
 
 281  
     @Override
 282  
     public void setIncludeEmptyDirs( final boolean includeEmptyDirs )
 283  
     {
 284  6
         this.includeEmptyDirs = includeEmptyDirs;
 285  6
     }
 286  
 
 287  
     @Override
 288  
     public void addDirectory( @Nonnull final File directory )
 289  
         throws ArchiverException
 290  
     {
 291  44
         addFileSet(
 292  0
             fileSet( directory ).prefixed( "" ).includeExclude( null, null ).includeEmptyDirs( includeEmptyDirs ) );
 293  44
     }
 294  
 
 295  
     @Override
 296  
     public void addDirectory( @Nonnull final File directory, final String prefix )
 297  
         throws ArchiverException
 298  
     {
 299  10
         addFileSet(
 300  0
             fileSet( directory ).prefixed( prefix ).includeExclude( null, null ).includeEmptyDirs( includeEmptyDirs ) );
 301  10
     }
 302  
 
 303  
     @Override
 304  
     public void addDirectory( @Nonnull final File directory, final String[] includes, final String[] excludes )
 305  
         throws ArchiverException
 306  
     {
 307  5
         addFileSet( fileSet( directory ).prefixed( "" ).includeExclude( includes, excludes ).includeEmptyDirs(
 308  0
             includeEmptyDirs ) );
 309  5
     }
 310  
 
 311  
     @Override
 312  
     public void addDirectory( @Nonnull final File directory, final String prefix, final String[] includes,
 313  
                               final String[] excludes )
 314  
         throws ArchiverException
 315  
     {
 316  0
         addFileSet( fileSet( directory ).prefixed( prefix ).includeExclude( includes, excludes ).includeEmptyDirs(
 317  0
             includeEmptyDirs ) );
 318  0
     }
 319  
 
 320  
     @Override
 321  
     public void addFileSet( @Nonnull final FileSet fileSet )
 322  
         throws ArchiverException
 323  
     {
 324  61
         final File directory = fileSet.getDirectory();
 325  61
         if ( directory == null )
 326  
         {
 327  0
             throw new ArchiverException( "The file sets base directory is null." );
 328  
         }
 329  
 
 330  61
         if ( !directory.isDirectory() )
 331  
         {
 332  0
             throw new ArchiverException( directory.getAbsolutePath() + " isn't a directory." );
 333  
         }
 334  
 
 335  
         // The PlexusIoFileResourceCollection contains platform-specific File.separatorChar which
 336  
         // is an interesting cause of grief, see PLXCOMP-192
 337  61
         final PlexusIoFileResourceCollection collection = new PlexusIoFileResourceCollection();
 338  61
         collection.setFollowingSymLinks( false );
 339  
 
 340  61
         collection.setIncludes( fileSet.getIncludes() );
 341  61
         collection.setExcludes( fileSet.getExcludes() );
 342  61
         collection.setBaseDir( directory );
 343  61
         collection.setFileSelectors( fileSet.getFileSelectors() );
 344  61
         collection.setIncludingEmptyDirectories( fileSet.isIncludingEmptyDirectories() );
 345  61
         collection.setPrefix( fileSet.getPrefix() );
 346  61
         collection.setCaseSensitive( fileSet.isCaseSensitive() );
 347  61
         collection.setUsingDefaultExcludes( fileSet.isUsingDefaultExcludes() );
 348  61
         collection.setStreamTransformer( fileSet.getStreamTransformer() );
 349  
 
 350  61
         if ( getOverrideDirectoryMode() > -1 || getOverrideFileMode() > -1 )
 351  
         {
 352  15
             collection.setOverrideAttributes( -1, null, -1, null, getOverrideFileMode(), getOverrideDirectoryMode() );
 353  
         }
 354  
 
 355  61
         if ( getDefaultDirectoryMode() > -1 || getDefaultFileMode() > -1 )
 356  
         {
 357  61
             collection.setDefaultAttributes( -1, null, -1, null, getDefaultFileMode(), getDefaultDirectoryMode() );
 358  
         }
 359  
 
 360  61
         addResources( collection );
 361  61
     }
 362  
 
 363  
     @Override
 364  
     public void addFile( @Nonnull final File inputFile, @Nonnull final String destFileName )
 365  
         throws ArchiverException
 366  
     {
 367  262
         final int fileMode = getOverrideFileMode();
 368  
 
 369  262
         addFile( inputFile, destFileName, fileMode );
 370  262
     }
 371  
 
 372  
     @Override
 373  
     public void addSymlink( String symlinkName, String symlinkDestination )
 374  
         throws ArchiverException
 375  
     {
 376  3
         final int fileMode = getOverrideFileMode();
 377  
 
 378  3
         addSymlink( symlinkName, fileMode, symlinkDestination );
 379  3
     }
 380  
 
 381  
     @Override
 382  
     public void addSymlink( String symlinkName, int permissions, String symlinkDestination )
 383  
         throws ArchiverException
 384  
     {
 385  3
         doAddResource(
 386  0
             ArchiveEntry.createSymlinkEntry( symlinkName, permissions, symlinkDestination, getDirectoryMode() ) );
 387  3
     }
 388  
 
 389  
     protected ArchiveEntry asArchiveEntry( @Nonnull final PlexusIoResource resource, final String destFileName,
 390  
                                            final int permissions, PlexusIoResourceCollection collection )
 391  
         throws ArchiverException
 392  
     {
 393  49472
         if ( !resource.isExisting() )
 394  
         {
 395  0
             throw new ArchiverException( resource.getName() + " not found." );
 396  
         }
 397  
 
 398  49472
         if ( resource.isFile() )
 399  
         {
 400  48228
             return ArchiveEntry.createFileEntry( destFileName, resource, permissions, collection, getDirectoryMode() );
 401  
         }
 402  
         else
 403  
         {
 404  1244
             return ArchiveEntry.createDirectoryEntry( destFileName, resource, permissions, getDirectoryMode() );
 405  
         }
 406  
     }
 407  
 
 408  0
     private ArchiveEntry asArchiveEntry( final AddedResourceCollection collection, final PlexusIoResource resource )
 409  
         throws ArchiverException
 410  
     {
 411  49471
         final String destFileName = collection.resources.getName( resource );
 412  
 
 413  49471
         int fromResource = PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE;
 414  49471
         if ( resource instanceof ResourceAttributeSupplier )
 415  
         {
 416  49453
             final PlexusIoResourceAttributes attrs = ( (ResourceAttributeSupplier) resource ).getAttributes();
 417  
 
 418  49453
             if ( attrs != null )
 419  
             {
 420  49453
                 fromResource = attrs.getOctalMode();
 421  
             }
 422  
         }
 423  
 
 424  49471
         return asArchiveEntry( resource, destFileName,
 425  0
                                collection.maybeOverridden( fromResource, resource.isDirectory() ),
 426  0
                                collection.resources );
 427  
     }
 428  
 
 429  
     @Override
 430  
     public void addResource( final PlexusIoResource resource, final String destFileName, final int permissions )
 431  
         throws ArchiverException
 432  
     {
 433  1
         doAddResource( asArchiveEntry( resource, destFileName, permissions, null ) );
 434  1
     }
 435  
 
 436  
     @Override
 437  
     public void addFile( @Nonnull final File inputFile, @Nonnull String destFileName, int permissions )
 438  
         throws ArchiverException
 439  
     {
 440  274
         if ( !inputFile.isFile() || !inputFile.exists() )
 441  
         {
 442  0
             throw new ArchiverException( inputFile.getAbsolutePath() + " isn't a file." );
 443  
         }
 444  
 
 445  274
         if ( replacePathSlashesToJavaPaths )
 446  
         {
 447  274
             destFileName = destFileName.replace( '\\', '/' );
 448  
         }
 449  
 
 450  274
         if ( permissions < 0 )
 451  
         {
 452  253
             permissions = getOverrideFileMode();
 453  
         }
 454  
 
 455  
         try
 456  
         {
 457  
             // do a null check here, to avoid creating a file stream if there are no filters...
 458  274
             doAddResource( ArchiveEntry.createFileEntry( destFileName, inputFile, permissions, getDirectoryMode() ) );
 459  0
         }
 460  0
         catch ( final IOException e )
 461  
         {
 462  0
             throw new ArchiverException( "Failed to determine inclusion status for: " + inputFile, e );
 463  274
         }
 464  274
     }
 465  
 
 466  
     @Nonnull
 467  
     @Override
 468  
     public ResourceIterator getResources()
 469  
         throws ArchiverException
 470  
     {
 471  0
         return new ResourceIterator()
 472  107
         {
 473  
 
 474  107
             private final Iterator addedResourceIter = resources.iterator();
 475  
 
 476  
             private AddedResourceCollection currentResourceCollection;
 477  
 
 478  
             private Iterator ioResourceIter;
 479  
 
 480  
             private ArchiveEntry nextEntry;
 481  
 
 482  107
             private final Set<String> seenEntries = new HashSet<String>();
 483  
 
 484  
             @Override
 485  
             public boolean hasNext()
 486  
             {
 487  
                 do
 488  
                 {
 489  99735
                     if ( nextEntry == null )
 490  
                     {
 491  49931
                         if ( ioResourceIter == null )
 492  
                         {
 493  389
                             if ( addedResourceIter.hasNext() )
 494  
                             {
 495  343
                                 final Object o = addedResourceIter.next();
 496  343
                                 if ( o instanceof ArchiveEntry )
 497  
                                 {
 498  272
                                     nextEntry = (ArchiveEntry) o;
 499  0
                                 }
 500  71
                                 else if ( o instanceof AddedResourceCollection )
 501  
                                 {
 502  71
                                     currentResourceCollection = (AddedResourceCollection) o;
 503  
 
 504  
                                     try
 505  
                                     {
 506  71
                                         ioResourceIter = currentResourceCollection.resources.getResources();
 507  0
                                     }
 508  0
                                     catch ( final IOException e )
 509  
                                     {
 510  0
                                         throw new ArchiverException( e.getMessage(), e );
 511  71
                                     }
 512  
                                 }
 513  
                                 else
 514  
                                 {
 515  0
                                     return throwIllegalResourceType( o );
 516  
                                 }
 517  343
                             }
 518  
                             else
 519  
                             {
 520  46
                                 nextEntry = null;
 521  
                             }
 522  0
                         }
 523  
                         else
 524  
                         {
 525  49542
                             if ( ioResourceIter.hasNext() )
 526  
                             {
 527  49471
                                 final PlexusIoResource resource = (PlexusIoResource) ioResourceIter.next();
 528  49471
                                 nextEntry = asArchiveEntry( currentResourceCollection, resource );
 529  49471
                             }
 530  
                             else
 531  
                             {
 532  
                                 // this will leak handles in the IO iterator if the iterator is not fully consumed.
 533  
                                 // alternately we'd have to make this method return a Closeable iterator back
 534  
                                 // to the client and ditch the whole issue onto the client.
 535  
                                 // this does not really make any sense either, might equally well change the
 536  
                                 // api into something that is not broken by design.
 537  71
                                 addCloseable( ioResourceIter );
 538  71
                                 ioResourceIter = null;
 539  
                             }
 540  
                         }
 541  
                     }
 542  
 
 543  99735
                     if ( nextEntry != null && seenEntries.contains( normalizedForDuplicateCheck( nextEntry ) ) )
 544  
                     {
 545  15
                         final String path = nextEntry.getName();
 546  
 
 547  15
                         if ( Archiver.DUPLICATES_PRESERVE.equals( duplicateBehavior )
 548  0
                                  || Archiver.DUPLICATES_SKIP.equals( duplicateBehavior ) )
 549  
                         {
 550  15
                             if ( nextEntry.getType() == ArchiveEntry.FILE )
 551  
                             {
 552  14
                                 getLogger().debug( path + " already added, skipping" );
 553  
                             }
 554  
 
 555  15
                             nextEntry = null;
 556  0
                         }
 557  0
                         else if ( Archiver.DUPLICATES_FAIL.equals( duplicateBehavior ) )
 558  
                         {
 559  0
                             throw new ArchiverException(
 560  0
                                 "Duplicate file " + path + " was found and the duplicate " + "attribute is 'fail'." );
 561  
                         }
 562  
                         else
 563  
                         {
 564  
                             // duplicate equal to add, so we continue
 565  0
                             getLogger().debug( "duplicate file " + path + " found, adding." );
 566  
                         }
 567  
                     }
 568  
                 }
 569  99735
                 while ( nextEntry == null && !( ioResourceIter == null && !addedResourceIter.hasNext() ) );
 570  
 
 571  99640
                 return nextEntry != null;
 572  
             }
 573  
 
 574  
             private boolean throwIllegalResourceType( Object o )
 575  
             {
 576  0
                 throw new IllegalStateException(
 577  0
                     "An invalid resource of type: " + o.getClass().getName() + " was added to archiver: "
 578  0
                         + getClass().getName() );
 579  
             }
 580  
 
 581  
             @Override
 582  
             public ArchiveEntry next()
 583  
             {
 584  49728
                 if ( !hasNext() )
 585  
                 {
 586  0
                     throw new NoSuchElementException();
 587  
                 }
 588  
 
 589  49728
                 final ArchiveEntry next = nextEntry;
 590  49728
                 nextEntry = null;
 591  
 
 592  49728
                 seenEntries.add( normalizedForDuplicateCheck( next ) );
 593  
 
 594  49728
                 return next;
 595  
             }
 596  
 
 597  
             @Override
 598  
             public void remove()
 599  
             {
 600  0
                 throw new UnsupportedOperationException( "Does not support iterator" );
 601  
             }
 602  
 
 603  
             private String normalizedForDuplicateCheck( ArchiveEntry entry )
 604  
             {
 605  149275
                 return entry.getName().replace( '\\', '/' );
 606  
             }
 607  
 
 608  
         };
 609  
 
 610  
     }
 611  
 
 612  
     private static void closeIfCloseable( Object resource )
 613  
         throws IOException
 614  
     {
 615  356
         if ( resource == null )
 616  
         {
 617  0
             return;
 618  
         }
 619  356
         if ( resource instanceof Closeable )
 620  
         {
 621  16
             ( (Closeable) resource ).close();
 622  
         }
 623  
 
 624  356
     }
 625  
 
 626  
     private static void closeQuietlyIfCloseable( Object resource )
 627  
     {
 628  
         try
 629  
         {
 630  16
             closeIfCloseable( resource );
 631  0
         }
 632  0
         catch ( IOException e )
 633  
         {
 634  0
             throw new RuntimeException( e );
 635  16
         }
 636  16
     }
 637  
 
 638  
     @Override
 639  
     public Map<String, ArchiveEntry> getFiles()
 640  
     {
 641  
         try
 642  
         {
 643  0
             final Map<String, ArchiveEntry> map = new HashMap<String, ArchiveEntry>();
 644  0
             for ( final ResourceIterator iter = getResources(); iter.hasNext(); )
 645  
             {
 646  0
                 final ArchiveEntry entry = iter.next();
 647  0
                 if ( includeEmptyDirs || entry.getType() == ArchiveEntry.FILE )
 648  
                 {
 649  0
                     map.put( entry.getName(), entry );
 650  
                 }
 651  0
             }
 652  0
             return map;
 653  
         }
 654  0
         catch ( final ArchiverException e )
 655  
         {
 656  0
             throw new UndeclaredThrowableException( e );
 657  
         }
 658  
     }
 659  
 
 660  
     @Override
 661  
     public File getDestFile()
 662  
     {
 663  47491
         return destFile;
 664  
     }
 665  
 
 666  
     @Override
 667  
     public void setDestFile( final File destFile )
 668  
     {
 669  117
         this.destFile = destFile;
 670  
 
 671  117
         if ( destFile != null )
 672  
         {
 673  117
             destFile.getParentFile().mkdirs();
 674  
         }
 675  117
     }
 676  
 
 677  
     @Override
 678  
     protected Logger getLogger()
 679  
     {
 680  48503
         if ( logger == null )
 681  
         {
 682  84
             if ( super.getLogger() != null )
 683  
             {
 684  76
                 logger = super.getLogger();
 685  0
             }
 686  
             else
 687  
             {
 688  8
                 logger = new ConsoleLogger( Logger.LEVEL_INFO, "console" );
 689  
             }
 690  
         }
 691  
 
 692  48503
         return logger;
 693  
     }
 694  
 
 695  
     protected PlexusIoResourceCollection asResourceCollection( final ArchivedFileSet fileSet, Charset charset )
 696  
         throws ArchiverException
 697  
     {
 698  14
         final File archiveFile = fileSet.getArchive();
 699  
 
 700  
         final PlexusIoResourceCollection resources;
 701  
         try
 702  
         {
 703  14
             resources = archiverManager.getResourceCollection( archiveFile );
 704  0
         }
 705  0
         catch ( final NoSuchArchiverException e )
 706  
         {
 707  0
             throw new ArchiverException(
 708  0
                 "Error adding archived file-set. PlexusIoResourceCollection not found for: " + archiveFile, e );
 709  14
         }
 710  
 
 711  14
         if ( resources instanceof EncodingSupported )
 712  
         {
 713  6
             ( (EncodingSupported) resources ).setEncoding( charset );
 714  
         }
 715  
 
 716  14
         if ( resources instanceof PlexusIoArchivedResourceCollection )
 717  
         {
 718  14
             ( (PlexusIoArchivedResourceCollection) resources ).setFile( fileSet.getArchive() );
 719  0
         }
 720  
         else
 721  
         {
 722  0
             throw new ArchiverException( "Expected " + PlexusIoArchivedResourceCollection.class.getName() + ", got "
 723  0
                                              + resources.getClass().getName() );
 724  
         }
 725  
 
 726  14
         if ( resources instanceof AbstractPlexusIoResourceCollection )
 727  
         {
 728  10
             ( (AbstractPlexusIoResourceCollection) resources ).setStreamTransformer( fileSet.getStreamTransformer() );
 729  
         }
 730  14
         final PlexusIoProxyResourceCollection proxy = new PlexusIoProxyResourceCollection( resources );
 731  
 
 732  14
         proxy.setExcludes( fileSet.getExcludes() );
 733  14
         proxy.setIncludes( fileSet.getIncludes() );
 734  14
         proxy.setIncludingEmptyDirectories( fileSet.isIncludingEmptyDirectories() );
 735  14
         proxy.setCaseSensitive( fileSet.isCaseSensitive() );
 736  14
         proxy.setPrefix( fileSet.getPrefix() );
 737  14
         proxy.setUsingDefaultExcludes( fileSet.isUsingDefaultExcludes() );
 738  14
         proxy.setFileSelectors( fileSet.getFileSelectors() );
 739  14
         proxy.setStreamTransformer( fileSet.getStreamTransformer() );
 740  
 
 741  14
         if ( getOverrideDirectoryMode() > -1 || getOverrideFileMode() > -1 )
 742  
         {
 743  1
             proxy.setOverrideAttributes( -1, null, -1, null, getOverrideFileMode(), getOverrideDirectoryMode() );
 744  
         }
 745  
 
 746  14
         if ( getDefaultDirectoryMode() > -1 || getDefaultFileMode() > -1 )
 747  
         {
 748  14
             proxy.setDefaultAttributes( -1, null, -1, null, getDefaultFileMode(), getDefaultDirectoryMode() );
 749  
         }
 750  
 
 751  14
         return proxy;
 752  
     }
 753  
 
 754  
     /**
 755  
      * Adds a resource collection to the archive.
 756  
      */
 757  
     @Override
 758  
     public void addResources( final PlexusIoResourceCollection collection )
 759  
         throws ArchiverException
 760  
     {
 761  80
         doAddResource( new AddedResourceCollection( collection, forcedFileMode, forcedDirectoryMode ) );
 762  80
     }
 763  
 
 764  
     private void doAddResource( Object item )
 765  
     {
 766  358
         resources.add( item );
 767  358
     }
 768  
 
 769  
     @Override
 770  
     public void addArchivedFileSet( final ArchivedFileSet fileSet )
 771  
         throws ArchiverException
 772  
     {
 773  13
         final PlexusIoResourceCollection resourceCollection = asResourceCollection( fileSet, null );
 774  13
         addResources( resourceCollection );
 775  13
     }
 776  
 
 777  
     @Override
 778  
     public void addArchivedFileSet( final ArchivedFileSet fileSet, Charset charset )
 779  
         throws ArchiverException
 780  
     {
 781  1
         final PlexusIoResourceCollection resourceCollection = asResourceCollection( fileSet, charset );
 782  1
         addResources( resourceCollection );
 783  1
     }
 784  
 
 785  
     /**
 786  
      * @since 1.0-alpha-7
 787  
      */
 788  
     @Override
 789  
     public void addArchivedFileSet( @Nonnull final File archiveFile, final String prefix, final String[] includes,
 790  
                                     final String[] excludes )
 791  
         throws ArchiverException
 792  
     {
 793  0
         addArchivedFileSet(
 794  0
             archivedFileSet( archiveFile ).prefixed( prefix ).includeExclude( includes, excludes ).includeEmptyDirs(
 795  0
                 includeEmptyDirs ) );
 796  0
     }
 797  
 
 798  
     /**
 799  
      * @since 1.0-alpha-7
 800  
      */
 801  
     @Override
 802  
     public void addArchivedFileSet( @Nonnull final File archiveFile, final String prefix )
 803  
         throws ArchiverException
 804  
     {
 805  6
         addArchivedFileSet( archivedFileSet( archiveFile ).prefixed( prefix ).includeEmptyDirs( includeEmptyDirs ) );
 806  6
     }
 807  
 
 808  
     /**
 809  
      * @since 1.0-alpha-7
 810  
      */
 811  
     @Override
 812  
     public void addArchivedFileSet( @Nonnull final File archiveFile, final String[] includes, final String[] excludes )
 813  
         throws ArchiverException
 814  
     {
 815  0
         addArchivedFileSet(
 816  0
             archivedFileSet( archiveFile ).includeExclude( includes, excludes ).includeEmptyDirs( includeEmptyDirs ) );
 817  0
     }
 818  
 
 819  
     /**
 820  
      * @since 1.0-alpha-7
 821  
      */
 822  
     @Override
 823  
     public void addArchivedFileSet( @Nonnull final File archiveFile )
 824  
         throws ArchiverException
 825  
     {
 826  3
         addArchivedFileSet( archivedFileSet( archiveFile ).includeEmptyDirs( includeEmptyDirs ) );
 827  3
     }
 828  
 
 829  
     /**
 830  
      * Allows us to pull the ArchiverManager instance out of the container without causing a chicken-and-egg
 831  
      * instantiation/composition problem.
 832  
      */
 833  
     @Override
 834  
     public void contextualize( final Context context )
 835  
         throws ContextException
 836  
     {
 837  108
         final PlexusContainer container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
 838  
 
 839  
         try
 840  
         {
 841  108
             archiverManager = (ArchiverManager) container.lookup( ArchiverManager.ROLE );
 842  0
         }
 843  0
         catch ( final ComponentLookupException e )
 844  
         {
 845  0
             throw new ContextException( "Error retrieving ArchiverManager instance: " + e.getMessage(), e );
 846  108
         }
 847  108
     }
 848  
 
 849  
     @Override
 850  
     public boolean isForced()
 851  
     {
 852  108
         return forced;
 853  
     }
 854  
 
 855  
     @Override
 856  
     public void setForced( final boolean forced )
 857  
     {
 858  11
         this.forced = forced;
 859  11
     }
 860  
 
 861  
     @Override
 862  
     public void addArchiveFinalizer( final ArchiveFinalizer finalizer )
 863  
     {
 864  2
         if ( finalizers == null )
 865  
         {
 866  2
             finalizers = new ArrayList<ArchiveFinalizer>();
 867  
         }
 868  
 
 869  2
         finalizers.add( finalizer );
 870  2
     }
 871  
 
 872  
     @Override
 873  
     public void setArchiveFinalizers( final List<ArchiveFinalizer> archiveFinalizers )
 874  
     {
 875  0
         finalizers = archiveFinalizers;
 876  0
     }
 877  
 
 878  
     @Override
 879  
     public void setDotFileDirectory( final File dotFileDirectory )
 880  
     {
 881  1
         this.dotFileDirectory = dotFileDirectory;
 882  1
     }
 883  
 
 884  
     protected boolean isUptodate()
 885  
         throws ArchiverException
 886  
     {
 887  6
         final File zipFile = getDestFile();
 888  6
         final long destTimestamp = zipFile.lastModified();
 889  6
         if ( destTimestamp == 0 )
 890  
         {
 891  0
             getLogger().debug( "isUp2date: false (Destination " + zipFile.getPath() + " not found.)" );
 892  0
             return false; // File doesn't yet exist
 893  
         }
 894  
 
 895  6
         final Iterator it = resources.iterator();
 896  6
         if ( !it.hasNext() )
 897  
         {
 898  0
             getLogger().debug( "isUp2date: false (No input files.)" );
 899  0
             return false; // No timestamp to compare
 900  
         }
 901  
 
 902  16
         while ( it.hasNext() )
 903  
         {
 904  10
             final Object o = it.next();
 905  
             final long l;
 906  10
             if ( o instanceof ArchiveEntry )
 907  
             {
 908  7
                 l = ( (ArchiveEntry) o ).getResource().getLastModified();
 909  0
             }
 910  3
             else if ( o instanceof AddedResourceCollection )
 911  
             {
 912  
                 try
 913  
                 {
 914  3
                     l = ( (AddedResourceCollection) o ).resources.getLastModified();
 915  0
                 }
 916  0
                 catch ( final IOException e )
 917  
                 {
 918  0
                     throw new ArchiverException( e.getMessage(), e );
 919  3
                 }
 920  
             }
 921  
             else
 922  
             {
 923  0
                 throw new IllegalStateException( "Invalid object type: " + o.getClass().getName() );
 924  
             }
 925  10
             if ( l == PlexusIoResource.UNKNOWN_MODIFICATION_DATE )
 926  
             {
 927  
                 // Don't know what to do. Safe thing is to assume not up2date.
 928  0
                 getLogger().debug( "isUp2date: false (Resource with unknown modification date found.)" );
 929  0
                 return false;
 930  
             }
 931  10
             if ( l > destTimestamp )
 932  
             {
 933  0
                 getLogger().debug( "isUp2date: false (Resource with newer modification date found.)" );
 934  0
                 return false;
 935  
             }
 936  10
         }
 937  
 
 938  6
         getLogger().debug( "isUp2date: true" );
 939  6
         return true;
 940  
     }
 941  
 
 942  
     protected boolean checkForced()
 943  
         throws ArchiverException
 944  
     {
 945  106
         if ( !isForced() && isSupportingForced() && isUptodate() )
 946  
         {
 947  6
             getLogger().debug( "Archive " + getDestFile() + " is uptodate." );
 948  6
             return false;
 949  
         }
 950  100
         return true;
 951  
     }
 952  
 
 953  
     @Override
 954  
     public boolean isSupportingForced()
 955  
     {
 956  0
         return false;
 957  
     }
 958  
 
 959  
     protected void runArchiveFinalizers()
 960  
         throws ArchiverException
 961  
     {
 962  109
         if ( finalizers != null )
 963  
         {
 964  2
             for ( final ArchiveFinalizer finalizer : finalizers )
 965  
             {
 966  2
                 finalizer.finalizeArchiveCreation( this );
 967  2
             }
 968  
         }
 969  109
     }
 970  
 
 971  
     @Override
 972  
     public final void createArchive()
 973  
         throws ArchiverException, IOException
 974  
     {
 975  109
         validate();
 976  
         try
 977  
         {
 978  
             try
 979  
             {
 980  109
                 if ( dotFileDirectory != null )
 981  
                 {
 982  1
                     addArchiveFinalizer( new DotDirectiveArchiveFinalizer( dotFileDirectory ) );
 983  
                 }
 984  
 
 985  109
                 runArchiveFinalizers();
 986  
 
 987  109
                 execute();
 988  0
             }
 989  
             finally
 990  0
             {
 991  109
                 close();
 992  103
             }
 993  0
         }
 994  0
         catch ( final IOException e )
 995  
         {
 996  0
             String msg = "Problem creating " + getArchiveType() + ": " + e.getMessage();
 997  
 
 998  0
             final StringBuffer revertBuffer = new StringBuffer();
 999  0
             if ( !revert( revertBuffer ) )
 1000  
             {
 1001  0
                 msg += revertBuffer.toString();
 1002  
             }
 1003  
 
 1004  0
             throw new ArchiverException( msg, e );
 1005  
         }
 1006  
         finally
 1007  0
         {
 1008  109
             cleanUp();
 1009  103
         }
 1010  
 
 1011  103
         postCreateArchive();
 1012  103
     }
 1013  
 
 1014  
     protected boolean hasVirtualFiles()
 1015  
     {
 1016  1
         if ( finalizers != null )
 1017  
         {
 1018  0
             for ( final ArchiveFinalizer finalizer : finalizers )
 1019  
             {
 1020  0
                 final List virtualFiles = finalizer.getVirtualFiles();
 1021  
 
 1022  0
                 if ( ( virtualFiles != null ) && !virtualFiles.isEmpty() )
 1023  
                 {
 1024  0
                     return true;
 1025  
                 }
 1026  0
             }
 1027  
         }
 1028  1
         return false;
 1029  
     }
 1030  
 
 1031  
     protected boolean revert( final StringBuffer messageBuffer )
 1032  
     {
 1033  0
         return true;
 1034  
     }
 1035  
 
 1036  
     protected void validate()
 1037  
         throws ArchiverException, IOException
 1038  
     {
 1039  109
     }
 1040  
 
 1041  
     /**
 1042  
      * This method is called after the archive creation
 1043  
      * completes successfully (no exceptions are thrown).
 1044  
      *
 1045  
      * Subclasses may override this method in order to
 1046  
      * augment or validate the archive after it is
 1047  
      * created.
 1048  
      *
 1049  
      * @since 3.6
 1050  
      */
 1051  
     protected void postCreateArchive()
 1052  
         throws ArchiverException, IOException
 1053  
     {
 1054  101
     }
 1055  
 
 1056  
     protected abstract String getArchiveType();
 1057  
 
 1058  0
     private void addCloseable( Object maybeCloseable )
 1059  
     {
 1060  71
         if ( maybeCloseable instanceof Closeable )
 1061  
         {
 1062  16
             closeables.add( (Closeable) maybeCloseable );
 1063  
         }
 1064  
 
 1065  71
     }
 1066  
 
 1067  
     private void closeIterators()
 1068  
     {
 1069  109
         for ( Closeable closeable : closeables )
 1070  
         {
 1071  16
             closeQuietlyIfCloseable( closeable );
 1072  16
         }
 1073  
 
 1074  109
     }
 1075  
 
 1076  
     protected abstract void close()
 1077  
         throws IOException;
 1078  
 
 1079  
     protected void cleanUp()
 1080  
         throws IOException
 1081  
     {
 1082  109
         closeIterators();
 1083  
 
 1084  109
         for ( Object resource : resources )
 1085  
         {
 1086  340
             if ( resource instanceof PlexusIoProxyResourceCollection )
 1087  
             {
 1088  0
                 resource = ( (PlexusIoProxyResourceCollection) resource ).getSrc();
 1089  
             }
 1090  
 
 1091  340
             closeIfCloseable( resource );
 1092  340
         }
 1093  109
         resources.clear();
 1094  109
     }
 1095  
 
 1096  
     protected abstract void execute()
 1097  
         throws ArchiverException, IOException;
 1098  
 
 1099  
     /**
 1100  
      * @since 1.1
 1101  
      */
 1102  
     @Override
 1103  
     public boolean isUseJvmChmod()
 1104  
     {
 1105  0
         return useJvmChmod;
 1106  
     }
 1107  
 
 1108  
     /**
 1109  
      * @since 1.1
 1110  
      */
 1111  
     @Override
 1112  
     public void setUseJvmChmod( final boolean useJvmChmod )
 1113  
     {
 1114  0
         this.useJvmChmod = useJvmChmod;
 1115  0
     }
 1116  
 
 1117  
     /**
 1118  
      * @since 1.1
 1119  
      */
 1120  
     @Override
 1121  
     public boolean isIgnorePermissions()
 1122  
     {
 1123  18
         return ignorePermissions;
 1124  
     }
 1125  
 
 1126  
     /**
 1127  
      * @since 1.1
 1128  
      */
 1129  
     @Override
 1130  
     public void setIgnorePermissions( final boolean ignorePermissions )
 1131  
     {
 1132  0
         this.ignorePermissions = ignorePermissions;
 1133  0
     }
 1134  
 
 1135  
 }