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