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