View Javadoc
1   package org.apache.maven.plugin.assembly.archive.archiver;
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 org.apache.maven.plugin.assembly.filter.ContainerDescriptorHandler;
23  import org.codehaus.plexus.archiver.ArchiveEntry;
24  import org.codehaus.plexus.archiver.ArchiveFinalizer;
25  import org.codehaus.plexus.archiver.ArchivedFileSet;
26  import org.codehaus.plexus.archiver.Archiver;
27  import org.codehaus.plexus.archiver.ArchiverException;
28  import org.codehaus.plexus.archiver.FileSet;
29  import org.codehaus.plexus.archiver.FinalizerEnabled;
30  import org.codehaus.plexus.archiver.ResourceIterator;
31  import org.codehaus.plexus.archiver.util.DefaultArchivedFileSet;
32  import org.codehaus.plexus.archiver.util.DefaultFileSet;
33  import org.codehaus.plexus.components.io.fileselectors.FileInfo;
34  import org.codehaus.plexus.components.io.fileselectors.FileSelector;
35  import org.codehaus.plexus.components.io.resources.PlexusIoResource;
36  import org.codehaus.plexus.components.io.resources.PlexusIoResourceCollection;
37  import org.codehaus.plexus.logging.Logger;
38  
39  import javax.annotation.Nonnull;
40  import java.io.File;
41  import java.io.FileInputStream;
42  import java.io.IOException;
43  import java.io.InputStream;
44  import java.util.ArrayList;
45  import java.util.Arrays;
46  import java.util.HashSet;
47  import java.util.List;
48  import java.util.Map;
49  import java.util.Set;
50  
51  /**
52   * Delegating archiver implementation that supports:
53   * <ul>
54   * <li>dry-running (where the delegate archiver is never actually called)</li>
55   * <li>prefixing (where all paths have a set global prefix prepended before addition)</li>
56   * <li>duplication checks on archive additions (for archive-file path + prefix)</li>
57   * </ul>
58   *
59   * @author jdcasey
60   * @version $Id: AssemblyProxyArchiver.java 1633832 2014-10-23 15:03:47Z krosenvold $
61   */
62  public class AssemblyProxyArchiver
63      implements Archiver
64  {
65  
66      private final Archiver delegate;
67  
68      private String rootPrefix;
69  
70      private FileSelector[] selectors;
71  
72      private final ThreadLocal<Boolean> inPublicApi = new ThreadLocal<Boolean>();
73  
74      private final Logger logger;
75  
76      private final boolean dryRun;
77  
78      private boolean forced;
79  
80      private final Set<String> seenPaths = new HashSet<String>();
81  
82      private final String assemblyWorkPath;
83  
84      /**
85       * @since 2.2
86       */
87      private boolean useJvmChmod;
88  
89      public AssemblyProxyArchiver( final String rootPrefix, final Archiver delegate,
90                                    final List<ContainerDescriptorHandler> containerDescriptorHandlers,
91                                    final List<FileSelector> extraSelectors, final List<ArchiveFinalizer> extraFinalizers,
92                                    final File assemblyWorkDir, final Logger logger, final boolean dryRun )
93      {
94          this.rootPrefix = rootPrefix;
95          this.delegate = delegate;
96  
97          assemblyWorkPath = assemblyWorkDir.getAbsolutePath().replace( '\\', '/' );
98  
99          this.logger = logger;
100         this.dryRun = dryRun;
101 
102         if ( !"".equals( rootPrefix ) && !rootPrefix.endsWith( "/" ) )
103         {
104             this.rootPrefix += "/";
105         }
106 
107         final List<FileSelector> selectors = new ArrayList<FileSelector>();
108 
109         FinalizerEnabled finalizer = ( delegate instanceof FinalizerEnabled ) ? (FinalizerEnabled) delegate : null;
110 
111         if ( containerDescriptorHandlers != null )
112         {
113             for ( final ContainerDescriptorHandler handler : containerDescriptorHandlers )
114             {
115                 selectors.add( handler );
116 
117                 if ( finalizer != null )
118                 {
119                     finalizer.addArchiveFinalizer( handler );
120                 }
121             }
122         }
123 
124         if ( extraSelectors != null )
125         {
126             for ( final FileSelector selector : extraSelectors )
127             {
128                 selectors.add( selector );
129             }
130         }
131 
132         if ( ( extraFinalizers != null ) && finalizer != null )
133         {
134             for ( ArchiveFinalizer extraFinalizer : extraFinalizers )
135             {
136                 finalizer.addArchiveFinalizer( extraFinalizer );
137             }
138         }
139 
140         if ( !selectors.isEmpty() )
141         {
142             this.selectors = selectors.toArray( new FileSelector[selectors.size()] );
143         }
144     }
145 
146     /**
147      * {@inheritDoc}
148      */
149     public void addArchivedFileSet( final @Nonnull File archiveFile, final String prefix, final String[] includes,
150                                     final String[] excludes )
151     {
152         final String archiveKey = getArchiveKey( archiveFile, prefix );
153         if ( seenPaths.contains( archiveKey ) )
154         {
155             warn( "Archive: " + archiveFile + " has already been added. Skipping." );
156             return;
157         }
158 
159         inPublicApi.set( Boolean.TRUE );
160         try
161         {
162             final DefaultArchivedFileSet fs = new DefaultArchivedFileSet();
163 
164             fs.setArchive( archiveFile );
165             fs.setIncludes( includes );
166             fs.setExcludes( excludes );
167             fs.setPrefix( rootPrefix + prefix );
168             fs.setFileSelectors( selectors );
169 
170             debug( "Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix() );
171 
172             if ( dryRun )
173             {
174                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
175             }
176             else
177             {
178                 delegate.addArchivedFileSet( fs );
179                 seenPaths.add( archiveKey );
180             }
181         }
182         finally
183         {
184             inPublicApi.set( null );
185         }
186     }
187 
188     private String getArchiveKey( final File archiveFile, final String prefix )
189     {
190         return archiveFile.getAbsolutePath() + ":" + prefix;
191     }
192 
193     private void debug( final String message )
194     {
195         if ( ( logger != null ) && logger.isDebugEnabled() )
196         {
197             logger.debug( message );
198         }
199     }
200 
201     private void warn( final String message )
202     {
203         if ( ( logger != null ) && logger.isWarnEnabled() )
204         {
205             logger.warn( message );
206         }
207     }
208 
209     /**
210      * {@inheritDoc}
211      */
212     public void addArchivedFileSet( final @Nonnull File archiveFile, final String prefix )
213         throws ArchiverException
214     {
215         final String archiveKey = getArchiveKey( archiveFile, prefix );
216         if ( seenPaths.contains( archiveKey ) )
217         {
218             warn( "Archive: " + archiveFile + " has already been added. Skipping." );
219             return;
220         }
221 
222         inPublicApi.set( Boolean.TRUE );
223         try
224         {
225             final DefaultArchivedFileSet fs = new DefaultArchivedFileSet();
226 
227             fs.setArchive( archiveFile );
228             fs.setPrefix( rootPrefix + prefix );
229             fs.setFileSelectors( selectors );
230 
231             debug( "Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix() );
232 
233             if ( dryRun )
234             {
235                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
236             }
237             else
238             {
239                 delegate.addArchivedFileSet( fs );
240                 seenPaths.add( archiveKey );
241             }
242         }
243         finally
244         {
245             inPublicApi.set( null );
246         }
247     }
248 
249     /**
250      * {@inheritDoc}
251      */
252     public void addArchivedFileSet( final File archiveFile, final String[] includes, final String[] excludes )
253         throws ArchiverException
254     {
255         final String archiveKey = getArchiveKey( archiveFile, "" );
256         if ( seenPaths.contains( archiveKey ) )
257         {
258             warn( "Archive: " + archiveFile + " has already been added. Skipping." );
259             return;
260         }
261 
262         inPublicApi.set( Boolean.TRUE );
263         try
264         {
265             final DefaultArchivedFileSet fs = new DefaultArchivedFileSet();
266 
267             fs.setArchive( archiveFile );
268             fs.setIncludes( includes );
269             fs.setExcludes( excludes );
270             fs.setPrefix( rootPrefix );
271             fs.setFileSelectors( selectors );
272 
273             debug( "Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix() );
274 
275             if ( dryRun )
276             {
277                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
278             }
279             else
280             {
281                 delegate.addArchivedFileSet( fs );
282                 seenPaths.add( archiveKey );
283             }
284         }
285         finally
286         {
287             inPublicApi.set( null );
288         }
289     }
290 
291     /**
292      * {@inheritDoc}
293      */
294     public void addArchivedFileSet( final @Nonnull File archiveFile )
295         throws ArchiverException
296     {
297         final String archiveKey = getArchiveKey( archiveFile, "" );
298         if ( seenPaths.contains( archiveKey ) )
299         {
300             warn( "Archive: " + archiveFile + " has already been added. Skipping." );
301             return;
302         }
303 
304         inPublicApi.set( Boolean.TRUE );
305         try
306         {
307             final DefaultArchivedFileSet fs = new DefaultArchivedFileSet();
308 
309             fs.setArchive( archiveFile );
310             fs.setPrefix( rootPrefix );
311             fs.setFileSelectors( selectors );
312 
313             debug( "Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix() );
314 
315             if ( dryRun )
316             {
317                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
318             }
319             else
320             {
321                 delegate.addArchivedFileSet( fs );
322                 seenPaths.add( archiveKey );
323             }
324         }
325         finally
326         {
327             inPublicApi.set( null );
328         }
329     }
330 
331     /**
332      * {@inheritDoc}
333      */
334     public void addDirectory( final @Nonnull File directory, final String prefix, final String[] includes,
335                               final String[] excludes )
336         throws ArchiverException
337     {
338         inPublicApi.set( Boolean.TRUE );
339         try
340         {
341             final DefaultFileSet fs = new DefaultFileSet();
342 
343             fs.setDirectory( directory );
344             fs.setIncludes( includes );
345             fs.setExcludes( excludes );
346             fs.setPrefix( rootPrefix + prefix );
347             fs.setFileSelectors( selectors );
348 
349             debug( "Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix() );
350 
351             if ( dryRun )
352             {
353                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
354             }
355             else
356             {
357                 doAddFileSet( fs );
358             }
359         }
360         finally
361         {
362             inPublicApi.set( null );
363         }
364     }
365 
366     /**
367      * {@inheritDoc}
368      */
369     public void addSymlink( String symlinkName, String symlinkDestination )
370         throws ArchiverException
371     {
372         inPublicApi.set( Boolean.TRUE );
373         try
374         {
375             if ( dryRun )
376             {
377                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
378             }
379             else
380             {
381                 delegate.addSymlink( symlinkName, symlinkDestination );
382             }
383         }
384         finally
385         {
386             inPublicApi.set( null );
387         }
388 
389     }
390 
391     /**
392      * {@inheritDoc}
393      */
394     public void addSymlink( String symlinkName, int permissions, String symlinkDestination )
395         throws ArchiverException
396     {
397         inPublicApi.set( Boolean.TRUE );
398         try
399         {
400             if ( dryRun )
401             {
402                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
403             }
404             else
405             {
406                 delegate.addSymlink( symlinkName, permissions, symlinkDestination );
407             }
408 
409         }
410         finally
411         {
412             inPublicApi.set( null );
413         }
414 
415     }
416 
417     /**
418      * {@inheritDoc}
419      */
420     public void addDirectory( final @Nonnull File directory, final String prefix )
421         throws ArchiverException
422     {
423         inPublicApi.set( Boolean.TRUE );
424         try
425         {
426             final DefaultFileSet fs = new DefaultFileSet();
427 
428             fs.setDirectory( directory );
429             fs.setPrefix( rootPrefix + prefix );
430             fs.setFileSelectors( selectors );
431 
432             debug( "Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix() );
433 
434             if ( dryRun )
435             {
436                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
437             }
438             else
439             {
440                 doAddFileSet( fs );
441             }
442         }
443         finally
444         {
445             inPublicApi.set( null );
446         }
447     }
448 
449     /**
450      * {@inheritDoc}
451      */
452     public void addDirectory( final @Nonnull File directory, final String[] includes, final String[] excludes )
453         throws ArchiverException
454     {
455         inPublicApi.set( Boolean.TRUE );
456         try
457         {
458             final DefaultFileSet fs = new DefaultFileSet();
459 
460             fs.setDirectory( directory );
461             fs.setIncludes( includes );
462             fs.setExcludes( excludes );
463             fs.setPrefix( rootPrefix );
464             fs.setFileSelectors( selectors );
465 
466             debug( "Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix() );
467 
468             if ( dryRun )
469             {
470                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
471             }
472             else
473             {
474                 doAddFileSet( fs );
475             }
476         }
477         finally
478         {
479             inPublicApi.set( null );
480         }
481     }
482 
483     /**
484      * {@inheritDoc}
485      */
486     public void addDirectory( final @Nonnull File directory )
487         throws ArchiverException
488     {
489         inPublicApi.set( Boolean.TRUE );
490         try
491         {
492             final DefaultFileSet fs = new DefaultFileSet();
493 
494             fs.setDirectory( directory );
495             fs.setPrefix( rootPrefix );
496             fs.setFileSelectors( selectors );
497 
498             debug( "Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix() );
499 
500             if ( dryRun )
501             {
502                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
503             }
504             else
505             {
506                 doAddFileSet( fs );
507             }
508         }
509         finally
510         {
511             inPublicApi.set( null );
512         }
513     }
514 
515     /**
516      * {@inheritDoc}
517      */
518     public void addFile( final @Nonnull File inputFile, final @Nonnull String destFileName, final int permissions )
519         throws ArchiverException
520     {
521         if ( acceptFile( inputFile ) )
522         {
523             inPublicApi.set( Boolean.TRUE );
524             try
525             {
526                 debug( "Adding file: " + inputFile + " to archive location: " + rootPrefix + destFileName );
527 
528                 if ( dryRun )
529                 {
530                     debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
531                 }
532                 else
533                 {
534                     delegate.addFile( inputFile, rootPrefix + destFileName, permissions );
535                 }
536             }
537             finally
538             {
539                 inPublicApi.set( null );
540             }
541         }
542     }
543 
544     /**
545      * {@inheritDoc}
546      */
547     public void addFile( final @Nonnull File inputFile, final @Nonnull String destFileName )
548         throws ArchiverException
549     {
550         if ( acceptFile( inputFile ) )
551         {
552             inPublicApi.set( Boolean.TRUE );
553             try
554             {
555                 debug( "Adding file: " + inputFile + " to archive location: " + rootPrefix + destFileName );
556 
557                 if ( dryRun )
558                 {
559                     debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
560                 }
561                 else
562                 {
563                     delegate.addFile( inputFile, rootPrefix + destFileName );
564                 }
565             }
566             finally
567             {
568                 inPublicApi.set( null );
569             }
570         }
571     }
572 
573     /**
574      * {@inheritDoc}
575      */
576     public void createArchive()
577         throws ArchiverException, IOException
578     {
579         inPublicApi.set( Boolean.TRUE );
580         try
581         {
582             if ( dryRun )
583             {
584                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
585             }
586             else
587             {
588                 delegate.setForced( forced );
589                 delegate.createArchive();
590             }
591         }
592         finally
593         {
594             inPublicApi.set( null );
595         }
596     }
597 
598     /**
599      * {@inheritDoc}
600      */
601     public int getDefaultDirectoryMode()
602     {
603         inPublicApi.set( Boolean.TRUE );
604         try
605         {
606             return delegate.getDefaultDirectoryMode();
607         }
608         finally
609         {
610             inPublicApi.set( null );
611         }
612     }
613 
614     /**
615      * {@inheritDoc}
616      */
617     public int getDefaultFileMode()
618     {
619         inPublicApi.set( Boolean.TRUE );
620         try
621         {
622             return delegate.getDefaultFileMode();
623         }
624         finally
625         {
626             inPublicApi.set( null );
627         }
628     }
629 
630     /**
631      * {@inheritDoc}
632      */
633     public File getDestFile()
634     {
635         inPublicApi.set( Boolean.TRUE );
636         try
637         {
638             return delegate.getDestFile();
639         }
640         finally
641         {
642             inPublicApi.set( null );
643         }
644     }
645 
646     @SuppressWarnings( { "rawtypes", "deprecation" } )
647     /** {@inheritDoc} */ public Map<String, ArchiveEntry> getFiles()
648     {
649         inPublicApi.set( Boolean.TRUE );
650         try
651         {
652             return delegate.getFiles();
653         }
654         finally
655         {
656             inPublicApi.set( null );
657         }
658     }
659 
660     /**
661      * {@inheritDoc}
662      */
663     public boolean getIncludeEmptyDirs()
664     {
665         inPublicApi.set( Boolean.TRUE );
666         try
667         {
668             return delegate.getIncludeEmptyDirs();
669         }
670         finally
671         {
672             inPublicApi.set( null );
673         }
674     }
675 
676     /**
677      * {@inheritDoc}
678      */
679     public boolean isForced()
680     {
681         inPublicApi.set( Boolean.TRUE );
682         try
683         {
684             return delegate.isForced();
685         }
686         finally
687         {
688             inPublicApi.set( null );
689         }
690     }
691 
692     /**
693      * {@inheritDoc}
694      */
695     public boolean isSupportingForced()
696     {
697         inPublicApi.set( Boolean.TRUE );
698         try
699         {
700             return delegate.isSupportingForced();
701         }
702         finally
703         {
704             inPublicApi.set( null );
705         }
706     }
707 
708     /**
709      * {@inheritDoc}
710      */
711     public void setDefaultDirectoryMode( final int mode )
712     {
713         inPublicApi.set( Boolean.TRUE );
714         try
715         {
716             delegate.setDefaultDirectoryMode( mode );
717         }
718         finally
719         {
720             inPublicApi.set( null );
721         }
722     }
723 
724     /**
725      * {@inheritDoc}
726      */
727     public void setDefaultFileMode( final int mode )
728     {
729         inPublicApi.set( Boolean.TRUE );
730         try
731         {
732             delegate.setDefaultFileMode( mode );
733         }
734         finally
735         {
736             inPublicApi.set( null );
737         }
738     }
739 
740     /**
741      * {@inheritDoc}
742      */
743     public void setDestFile( final File destFile )
744     {
745         inPublicApi.set( Boolean.TRUE );
746         try
747         {
748             delegate.setDestFile( destFile );
749         }
750         finally
751         {
752             inPublicApi.set( null );
753         }
754     }
755 
756     /**
757      * {@inheritDoc}
758      */
759     public void setForced( final boolean forced )
760     {
761         inPublicApi.set( Boolean.TRUE );
762         try
763         {
764             this.forced = forced;
765             delegate.setForced( forced );
766         }
767         finally
768         {
769             inPublicApi.set( null );
770         }
771     }
772 
773     /**
774      * {@inheritDoc}
775      */
776     public void setIncludeEmptyDirs( final boolean includeEmptyDirs )
777     {
778         inPublicApi.set( Boolean.TRUE );
779         try
780         {
781             delegate.setIncludeEmptyDirs( includeEmptyDirs );
782         }
783         finally
784         {
785             inPublicApi.set( null );
786         }
787     }
788 
789     /**
790      * {@inheritDoc}
791      */
792     public void setDotFileDirectory( final File dotFileDirectory )
793     {
794         throw new UnsupportedOperationException(
795             "Undocumented feature of plexus-archiver; this is not yet supported." );
796     }
797 
798     /**
799      * {@inheritDoc}
800      */
801     public void addArchivedFileSet( final ArchivedFileSet fileSet )
802         throws ArchiverException
803     {
804         final String archiveKey = getArchiveKey( fileSet.getArchive(), "" );
805         if ( seenPaths.contains( archiveKey ) )
806         {
807             warn( "Archive: " + fileSet.getArchive() + " has already been added. Skipping." );
808             return;
809         }
810 
811         inPublicApi.set( Boolean.TRUE );
812         try
813         {
814             final PrefixedArchivedFileSet fs = new PrefixedArchivedFileSet( fileSet, rootPrefix, selectors );
815 
816             debug( "Adding archived file-set in: " + fileSet.getArchive() + " to archive location: " + fs.getPrefix() );
817 
818             if ( dryRun )
819             {
820                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
821             }
822             else
823             {
824                 delegate.addArchivedFileSet( fs );
825                 seenPaths.add( archiveKey );
826             }
827         }
828         finally
829         {
830             inPublicApi.set( null );
831         }
832     }
833 
834     /**
835      * {@inheritDoc}
836      */
837     public void addFileSet( final @Nonnull FileSet fileSet )
838         throws ArchiverException
839     {
840         inPublicApi.set( Boolean.TRUE );
841         try
842         {
843             final PrefixedFileSet fs = new PrefixedFileSet( fileSet, rootPrefix, selectors );
844 
845             debug( "Adding file-set in: " + fileSet.getDirectory() + " to archive location: " + fs.getPrefix() );
846 
847             if ( dryRun )
848             {
849                 debug( "DRY RUN: Skipping delegated call to: " + getMethodName() );
850             }
851             else
852             {
853                 doAddFileSet( fs );
854             }
855         }
856         finally
857         {
858             inPublicApi.set( null );
859         }
860     }
861 
862     private void doAddFileSet( final FileSet fs )
863         throws ArchiverException
864     {
865         final String fsPath = fs.getDirectory().getAbsolutePath().replace( '\\', '/' );
866 
867         if ( fsPath.equals( assemblyWorkPath ) )
868         {
869             logger.debug( "SKIPPING fileset with source directory matching assembly working-directory: " + fsPath );
870         }
871         else if ( assemblyWorkPath.startsWith( fsPath ) )
872         {
873             final List<String> newEx = new ArrayList<String>();
874             if ( fs.getExcludes() != null )
875             {
876                 newEx.addAll( Arrays.asList( fs.getExcludes() ) );
877             }
878 
879             final String workDirExclude = assemblyWorkPath.substring( fsPath.length() + 1 );
880 
881             logger.debug(
882                 "Adding exclude for assembly working-directory: " + workDirExclude + "\nFile-Set source directory: "
883                     + fsPath );
884 
885             newEx.add( workDirExclude );
886 
887             final List<String> newIn = new ArrayList<String>();
888             if ( fs.getIncludes() != null )
889             {
890                 for ( final String include : fs.getIncludes() )
891                 {
892                     if ( !include.startsWith( workDirExclude ) )
893                     {
894                         newIn.add( include );
895                     }
896                 }
897             }
898 
899             final DefaultFileSet dfs = new DefaultFileSet();
900 
901             dfs.setCaseSensitive( fs.isCaseSensitive() );
902             dfs.setDirectory( fs.getDirectory() );
903             dfs.setExcludes( newEx.toArray( new String[newEx.size()] ) );
904             dfs.setFileSelectors( fs.getFileSelectors() );
905             dfs.setIncludes( newIn.toArray( new String[newIn.size()] ) );
906             dfs.setIncludingEmptyDirectories( fs.isIncludingEmptyDirectories() );
907             dfs.setPrefix( fs.getPrefix() );
908             dfs.setUsingDefaultExcludes( fs.isUsingDefaultExcludes() );
909 
910             delegate.addFileSet( dfs );
911         }
912         else
913         {
914             delegate.addFileSet( fs );
915         }
916     }
917 
918     private String getMethodName()
919     {
920         final NullPointerException npe = new NullPointerException();
921         final StackTraceElement[] trace = npe.getStackTrace();
922 
923         final StackTraceElement methodElement = trace[1];
924 
925         return methodElement.getMethodName() + " (archiver line: " + methodElement.getLineNumber() + ")";
926     }
927 
928     private boolean acceptFile( final File inputFile )
929         throws ArchiverException
930     {
931         if ( Boolean.TRUE != inPublicApi.get() )
932         {
933             if ( selectors != null )
934             {
935                 final FileInfo fileInfo = new DefaultFileInfo( inputFile );
936 
937                 for ( final FileSelector selector : selectors )
938                 {
939                     try
940                     {
941                         if ( !selector.isSelected( fileInfo ) )
942                         {
943                             return false;
944                         }
945                     }
946                     catch ( final IOException e )
947                     {
948                         throw new ArchiverException(
949                             "Error processing file: " + inputFile + " using selector: " + selector, e );
950                     }
951                 }
952             }
953         }
954 
955         return true;
956     }
957 
958     private static final class DefaultFileInfo
959         implements FileInfo
960     {
961 
962         private final File inputFile;
963 
964         DefaultFileInfo( final File inputFile )
965         {
966             this.inputFile = inputFile;
967         }
968 
969         public InputStream getContents()
970             throws IOException
971         {
972             return new FileInputStream( inputFile );
973         }
974 
975         public String getName()
976         {
977             return inputFile.getName();
978         }
979 
980         public boolean isDirectory()
981         {
982             return inputFile.isDirectory();
983         }
984 
985         public boolean isFile()
986         {
987             return inputFile.isFile();
988         }
989 
990         public boolean isSymbolicLink()
991         {
992             return false;
993         }
994     }
995 
996     /**
997      * {@inheritDoc}
998      */
999     public void addResource( final PlexusIoResource resource, final String destFileName, final int permissions )
1000         throws ArchiverException
1001     {
1002         inPublicApi.set( Boolean.TRUE );
1003         try
1004         {
1005             delegate.addResource( resource, destFileName, permissions );
1006         }
1007         finally
1008         {
1009             inPublicApi.set( null );
1010         }
1011     }
1012 
1013     /**
1014      * {@inheritDoc}
1015      */
1016     public void addResources( final PlexusIoResourceCollection resources )
1017         throws ArchiverException
1018     {
1019         inPublicApi.set( Boolean.TRUE );
1020         try
1021         {
1022             delegate.addResources( resources );
1023         }
1024         finally
1025         {
1026             inPublicApi.set( null );
1027         }
1028     }
1029 
1030     /**
1031      * {@inheritDoc}
1032      */
1033     public
1034     @Nonnull
1035     ResourceIterator getResources()
1036         throws ArchiverException
1037     {
1038         return delegate.getResources();
1039     }
1040 
1041     /**
1042      * {@inheritDoc}
1043      */
1044     public String getDuplicateBehavior()
1045     {
1046         return delegate.getDuplicateBehavior();
1047     }
1048 
1049     /**
1050      * {@inheritDoc}
1051      */
1052     public void setDuplicateBehavior( final String duplicate )
1053     {
1054         inPublicApi.set( Boolean.TRUE );
1055         try
1056         {
1057             delegate.setDuplicateBehavior( duplicate );
1058         }
1059         finally
1060         {
1061             inPublicApi.set( null );
1062         }
1063     }
1064 
1065     /**
1066      * {@inheritDoc}
1067      */
1068     public int getDirectoryMode()
1069     {
1070         return delegate.getDirectoryMode();
1071     }
1072 
1073     /**
1074      * {@inheritDoc}
1075      */
1076     public int getFileMode()
1077     {
1078         return delegate.getFileMode();
1079     }
1080 
1081     /**
1082      * {@inheritDoc}
1083      */
1084     public int getOverrideDirectoryMode()
1085     {
1086         return delegate.getOverrideDirectoryMode();
1087     }
1088 
1089     /**
1090      * {@inheritDoc}
1091      */
1092     public int getOverrideFileMode()
1093     {
1094         return delegate.getOverrideFileMode();
1095     }
1096 
1097     /**
1098      * {@inheritDoc}
1099      */
1100     public void setDirectoryMode( final int mode )
1101     {
1102         inPublicApi.set( Boolean.TRUE );
1103         try
1104         {
1105             delegate.setDirectoryMode( mode );
1106         }
1107         finally
1108         {
1109             inPublicApi.set( null );
1110         }
1111     }
1112 
1113     /**
1114      * {@inheritDoc}
1115      */
1116     public void setFileMode( final int mode )
1117     {
1118         inPublicApi.set( Boolean.TRUE );
1119         try
1120         {
1121             delegate.setFileMode( mode );
1122         }
1123         finally
1124         {
1125             inPublicApi.set( null );
1126         }
1127     }
1128 
1129     /**
1130      * {@inheritDoc}
1131      */
1132     public boolean isUseJvmChmod()
1133     {
1134         return useJvmChmod;
1135     }
1136 
1137     /**
1138      * {@inheritDoc}
1139      */
1140     public void setUseJvmChmod( final boolean useJvmChmod )
1141     {
1142         this.useJvmChmod = useJvmChmod;
1143     }
1144 
1145     /**
1146      * {@inheritDoc}
1147      */
1148     public boolean isIgnorePermissions()
1149     {
1150         return delegate.isIgnorePermissions();
1151     }
1152 
1153     /**
1154      * {@inheritDoc}
1155      */
1156     public void setIgnorePermissions( final boolean ignorePermissions )
1157     {
1158         delegate.setIgnorePermissions( ignorePermissions );
1159     }
1160 
1161 }