View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.assembly.archive.archiver;
20  
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.nio.charset.Charset;
26  import java.nio.file.attribute.FileTime;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.Comparator;
30  import java.util.Date;
31  import java.util.List;
32  import java.util.Map;
33  
34  import org.apache.maven.plugins.assembly.filter.ContainerDescriptorHandler;
35  import org.codehaus.plexus.archiver.ArchiveEntry;
36  import org.codehaus.plexus.archiver.ArchiveFinalizer;
37  import org.codehaus.plexus.archiver.ArchivedFileSet;
38  import org.codehaus.plexus.archiver.Archiver;
39  import org.codehaus.plexus.archiver.ArchiverException;
40  import org.codehaus.plexus.archiver.FileSet;
41  import org.codehaus.plexus.archiver.FinalizerEnabled;
42  import org.codehaus.plexus.archiver.ResourceIterator;
43  import org.codehaus.plexus.archiver.util.DefaultArchivedFileSet;
44  import org.codehaus.plexus.archiver.util.DefaultFileSet;
45  import org.codehaus.plexus.components.io.fileselectors.FileInfo;
46  import org.codehaus.plexus.components.io.fileselectors.FileSelector;
47  import org.codehaus.plexus.components.io.resources.PlexusIoResource;
48  import org.codehaus.plexus.components.io.resources.PlexusIoResourceCollection;
49  import org.slf4j.Logger;
50  import org.slf4j.LoggerFactory;
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 implements Archiver {
64      private static final Logger LOGGER = LoggerFactory.getLogger(AssemblyProxyArchiver.class);
65  
66      private final Archiver delegate;
67  
68      private final ThreadLocal<Boolean> inPublicApi = new ThreadLocal<>();
69  
70      private final String assemblyWorkPath;
71  
72      private String rootPrefix;
73  
74      private FileSelector[] selectors;
75  
76      private boolean forced;
77  
78      /**
79       * @since 2.2
80       */
81      private boolean useJvmChmod;
82  
83      public AssemblyProxyArchiver(
84              final String rootPrefix,
85              final Archiver delegate,
86              final List<ContainerDescriptorHandler> containerDescriptorHandlers,
87              final List<FileSelector> extraSelectors,
88              final List<ArchiveFinalizer> extraFinalizers,
89              final File assemblyWorkDir) {
90          this.rootPrefix = rootPrefix;
91          this.delegate = delegate;
92  
93          assemblyWorkPath = assemblyWorkDir.getAbsolutePath().replace('\\', '/');
94  
95          if (!"".equals(rootPrefix) && !rootPrefix.endsWith("/")) {
96              this.rootPrefix += "/";
97          }
98  
99          final List<FileSelector> selectors = new ArrayList<>();
100 
101         FinalizerEnabled finalizer = (delegate instanceof FinalizerEnabled) ? (FinalizerEnabled) delegate : null;
102 
103         if (containerDescriptorHandlers != null) {
104             for (final ContainerDescriptorHandler handler : containerDescriptorHandlers) {
105                 selectors.add(handler);
106 
107                 if (finalizer != null) {
108                     finalizer.addArchiveFinalizer(handler);
109                 }
110             }
111         }
112 
113         if (extraSelectors != null) {
114             selectors.addAll(extraSelectors);
115         }
116 
117         if ((extraFinalizers != null) && finalizer != null) {
118             for (ArchiveFinalizer extraFinalizer : extraFinalizers) {
119                 finalizer.addArchiveFinalizer(extraFinalizer);
120             }
121         }
122 
123         if (!selectors.isEmpty()) {
124             this.selectors = selectors.toArray(new FileSelector[0]);
125         }
126     }
127 
128     /**
129      * {@inheritDoc}
130      */
131     @Override
132     public void addArchivedFileSet(
133             final File archiveFile, final String prefix, final String[] includes, final String[] excludes) {
134         inPublicApi.set(Boolean.TRUE);
135         try {
136             final DefaultArchivedFileSet fs = new DefaultArchivedFileSet(archiveFile);
137 
138             fs.setIncludes(includes);
139             fs.setExcludes(excludes);
140             fs.setPrefix(rootPrefix + prefix);
141             fs.setFileSelectors(selectors);
142 
143             debug("Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix());
144 
145             delegate.addArchivedFileSet(fs);
146         } finally {
147             inPublicApi.set(null);
148         }
149     }
150 
151     private void debug(final String message) {
152         if (LOGGER.isDebugEnabled()) {
153             LOGGER.debug(message);
154         }
155     }
156 
157     /**
158      * {@inheritDoc}
159      */
160     @Override
161     public void addArchivedFileSet(final File archiveFile, final String prefix) {
162         inPublicApi.set(Boolean.TRUE);
163         try {
164             final DefaultArchivedFileSet fs = new DefaultArchivedFileSet(archiveFile);
165 
166             fs.setPrefix(rootPrefix + prefix);
167             fs.setFileSelectors(selectors);
168 
169             debug("Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix());
170 
171             delegate.addArchivedFileSet(fs);
172         } finally {
173             inPublicApi.set(null);
174         }
175     }
176 
177     /**
178      * {@inheritDoc}
179      */
180     @Override
181     public void addArchivedFileSet(final File archiveFile, final String[] includes, final String[] excludes) {
182         inPublicApi.set(Boolean.TRUE);
183         try {
184             final DefaultArchivedFileSet fs = new DefaultArchivedFileSet(archiveFile);
185 
186             fs.setIncludes(includes);
187             fs.setExcludes(excludes);
188             fs.setPrefix(rootPrefix);
189             fs.setFileSelectors(selectors);
190 
191             debug("Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix());
192 
193             delegate.addArchivedFileSet(fs);
194         } finally {
195             inPublicApi.set(null);
196         }
197     }
198 
199     /**
200      * {@inheritDoc}
201      */
202     @Override
203     public void addArchivedFileSet(final File archiveFile) {
204         inPublicApi.set(Boolean.TRUE);
205         try {
206             final DefaultArchivedFileSet fs = new DefaultArchivedFileSet(archiveFile);
207 
208             fs.setPrefix(rootPrefix);
209             fs.setFileSelectors(selectors);
210 
211             debug("Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix());
212 
213             delegate.addArchivedFileSet(fs);
214         } finally {
215             inPublicApi.set(null);
216         }
217     }
218 
219     /**
220      * {@inheritDoc}
221      */
222     @Override
223     public void addDirectory(
224             final File directory, final String prefix, final String[] includes, final String[] excludes) {
225         inPublicApi.set(Boolean.TRUE);
226         try {
227             final DefaultFileSet fs = new DefaultFileSet();
228 
229             fs.setDirectory(directory);
230             fs.setIncludes(includes);
231             fs.setExcludes(excludes);
232             fs.setPrefix(rootPrefix + prefix);
233             fs.setFileSelectors(selectors);
234 
235             debug("Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix());
236 
237             doAddFileSet(fs);
238         } finally {
239             inPublicApi.set(null);
240         }
241     }
242 
243     /**
244      * {@inheritDoc}
245      */
246     @Override
247     public void addSymlink(String symlinkName, String symlinkDestination) {
248         inPublicApi.set(Boolean.TRUE);
249         try {
250             delegate.addSymlink(symlinkName, symlinkDestination);
251         } finally {
252             inPublicApi.set(null);
253         }
254     }
255 
256     /**
257      * {@inheritDoc}
258      */
259     @Override
260     public void addSymlink(String symlinkName, int permissions, String symlinkDestination) {
261         inPublicApi.set(Boolean.TRUE);
262         try {
263             delegate.addSymlink(symlinkName, permissions, symlinkDestination);
264         } finally {
265             inPublicApi.set(null);
266         }
267     }
268 
269     /**
270      * {@inheritDoc}
271      */
272     @Override
273     public void addDirectory(final File directory, final String prefix) {
274         inPublicApi.set(Boolean.TRUE);
275         try {
276             final DefaultFileSet fs = new DefaultFileSet();
277 
278             fs.setDirectory(directory);
279             fs.setPrefix(rootPrefix + prefix);
280             fs.setFileSelectors(selectors);
281 
282             debug("Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix());
283 
284             doAddFileSet(fs);
285         } finally {
286             inPublicApi.set(null);
287         }
288     }
289 
290     /**
291      * {@inheritDoc}
292      */
293     @Override
294     public void addDirectory(final File directory, final String[] includes, final String[] excludes) {
295         inPublicApi.set(Boolean.TRUE);
296         try {
297             final DefaultFileSet fs = new DefaultFileSet();
298 
299             fs.setDirectory(directory);
300             fs.setIncludes(includes);
301             fs.setExcludes(excludes);
302             fs.setPrefix(rootPrefix);
303             fs.setFileSelectors(selectors);
304 
305             debug("Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix());
306 
307             doAddFileSet(fs);
308         } finally {
309             inPublicApi.set(null);
310         }
311     }
312 
313     /**
314      * {@inheritDoc}
315      */
316     @Override
317     public void addDirectory(final File directory) {
318         inPublicApi.set(Boolean.TRUE);
319         try {
320             final DefaultFileSet fs = new DefaultFileSet();
321 
322             fs.setDirectory(directory);
323             fs.setPrefix(rootPrefix);
324             fs.setFileSelectors(selectors);
325 
326             debug("Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix());
327 
328             doAddFileSet(fs);
329         } finally {
330             inPublicApi.set(null);
331         }
332     }
333 
334     /**
335      * {@inheritDoc}
336      */
337     @Override
338     public void addFile(final File inputFile, final String destFileName, final int permissions) {
339         if (acceptFile(inputFile)) {
340             inPublicApi.set(Boolean.TRUE);
341             try {
342                 debug("Adding file: " + inputFile + " to archive location: " + rootPrefix + destFileName);
343 
344                 delegate.addFile(inputFile, rootPrefix + destFileName, permissions);
345             } finally {
346                 inPublicApi.set(null);
347             }
348         }
349     }
350 
351     /**
352      * {@inheritDoc}
353      */
354     @Override
355     public void addFile(final File inputFile, final String destFileName) {
356         if (acceptFile(inputFile)) {
357             inPublicApi.set(Boolean.TRUE);
358             try {
359                 debug("Adding file: " + inputFile + " to archive location: " + rootPrefix + destFileName);
360 
361                 delegate.addFile(inputFile, rootPrefix + destFileName);
362             } finally {
363                 inPublicApi.set(null);
364             }
365         }
366     }
367 
368     /**
369      * {@inheritDoc}
370      */
371     @Override
372     public void createArchive() throws IOException {
373         inPublicApi.set(Boolean.TRUE);
374         try {
375             delegate.setForced(forced);
376             delegate.createArchive();
377         } finally {
378             inPublicApi.set(null);
379         }
380     }
381 
382     /**
383      * {@inheritDoc}
384      */
385     @Override
386     public int getDefaultDirectoryMode() {
387         inPublicApi.set(Boolean.TRUE);
388         try {
389             return delegate.getDefaultDirectoryMode();
390         } finally {
391             inPublicApi.set(null);
392         }
393     }
394 
395     /**
396      * {@inheritDoc}
397      */
398     @Override
399     public void setDefaultDirectoryMode(final int mode) {
400         inPublicApi.set(Boolean.TRUE);
401         try {
402             delegate.setDefaultDirectoryMode(mode);
403         } finally {
404             inPublicApi.set(null);
405         }
406     }
407 
408     /**
409      * {@inheritDoc}
410      */
411     @Override
412     public int getDefaultFileMode() {
413         inPublicApi.set(Boolean.TRUE);
414         try {
415             return delegate.getDefaultFileMode();
416         } finally {
417             inPublicApi.set(null);
418         }
419     }
420 
421     /**
422      * {@inheritDoc}
423      */
424     @Override
425     public void setDefaultFileMode(final int mode) {
426         inPublicApi.set(Boolean.TRUE);
427         try {
428             delegate.setDefaultFileMode(mode);
429         } finally {
430             inPublicApi.set(null);
431         }
432     }
433 
434     /**
435      * {@inheritDoc}
436      */
437     @Override
438     public File getDestFile() {
439         inPublicApi.set(Boolean.TRUE);
440         try {
441             return delegate.getDestFile();
442         } finally {
443             inPublicApi.set(null);
444         }
445     }
446 
447     /**
448      * {@inheritDoc}
449      */
450     @Override
451     public void setDestFile(final File destFile) {
452         inPublicApi.set(Boolean.TRUE);
453         try {
454             delegate.setDestFile(destFile);
455         } finally {
456             inPublicApi.set(null);
457         }
458     }
459 
460     @Override
461     @SuppressWarnings({"deprecation"})
462     public Map<String, ArchiveEntry> getFiles() {
463         inPublicApi.set(Boolean.TRUE);
464         try {
465             return delegate.getFiles();
466         } finally {
467             inPublicApi.set(null);
468         }
469     }
470 
471     /**
472      * {@inheritDoc}
473      */
474     @Override
475     public boolean getIncludeEmptyDirs() {
476         inPublicApi.set(Boolean.TRUE);
477         try {
478             return delegate.getIncludeEmptyDirs();
479         } finally {
480             inPublicApi.set(null);
481         }
482     }
483 
484     /**
485      * {@inheritDoc}
486      */
487     @Override
488     public void setIncludeEmptyDirs(final boolean includeEmptyDirs) {
489         inPublicApi.set(Boolean.TRUE);
490         try {
491             delegate.setIncludeEmptyDirs(includeEmptyDirs);
492         } finally {
493             inPublicApi.set(null);
494         }
495     }
496 
497     /**
498      * {@inheritDoc}
499      */
500     @Override
501     public boolean isForced() {
502         inPublicApi.set(Boolean.TRUE);
503         try {
504             return delegate.isForced();
505         } finally {
506             inPublicApi.set(null);
507         }
508     }
509 
510     /**
511      * {@inheritDoc}
512      */
513     @Override
514     public void setForced(final boolean forced) {
515         inPublicApi.set(Boolean.TRUE);
516         try {
517             this.forced = forced;
518             delegate.setForced(forced);
519         } finally {
520             inPublicApi.set(null);
521         }
522     }
523 
524     /**
525      * {@inheritDoc}
526      */
527     @Override
528     public boolean isSupportingForced() {
529         inPublicApi.set(Boolean.TRUE);
530         try {
531             return delegate.isSupportingForced();
532         } finally {
533             inPublicApi.set(null);
534         }
535     }
536 
537     /**
538      * {@inheritDoc}
539      */
540     @Override
541     public void setDotFileDirectory(final File dotFileDirectory) {
542         throw new UnsupportedOperationException("Undocumented feature of plexus-archiver; this is not yet supported.");
543     }
544 
545     /**
546      * {@inheritDoc}
547      */
548     @Override
549     public void addArchivedFileSet(final ArchivedFileSet fileSet) {
550         inPublicApi.set(Boolean.TRUE);
551         try {
552             final PrefixedArchivedFileSet fs = new PrefixedArchivedFileSet(fileSet, rootPrefix, selectors);
553 
554             debug("Adding archived file-set in: " + fileSet.getArchive() + " to archive location: " + fs.getPrefix());
555 
556             delegate.addArchivedFileSet(fs);
557         } finally {
558             inPublicApi.set(null);
559         }
560     }
561 
562     @Override
563     public void addArchivedFileSet(ArchivedFileSet archivedFileSet, Charset charset) {
564         inPublicApi.set(Boolean.TRUE);
565         try {
566             final PrefixedArchivedFileSet fs = new PrefixedArchivedFileSet(archivedFileSet, rootPrefix, selectors);
567 
568             debug("Adding archived file-set in: " + archivedFileSet.getArchive() + " to archive location: "
569                     + fs.getPrefix());
570 
571             delegate.addArchivedFileSet(fs, charset);
572         } finally {
573             inPublicApi.set(null);
574         }
575     }
576 
577     /**
578      * {@inheritDoc}
579      */
580     @Override
581     public void addFileSet(final FileSet fileSet) {
582         inPublicApi.set(Boolean.TRUE);
583         try {
584             final PrefixedFileSet fs = new PrefixedFileSet(fileSet, rootPrefix, selectors);
585 
586             debug("Adding file-set in: " + fileSet.getDirectory() + " to archive location: " + fs.getPrefix());
587 
588             doAddFileSet(fs);
589         } finally {
590             inPublicApi.set(null);
591         }
592     }
593 
594     private void doAddFileSet(final FileSet fs) {
595         final String fsPath = fs.getDirectory().getAbsolutePath().replace('\\', '/');
596 
597         if (fsPath.equals(assemblyWorkPath)) {
598             LOGGER.debug("SKIPPING fileset with source directory matching assembly working-directory: " + fsPath);
599         } else if (assemblyWorkPath.startsWith(fsPath)) {
600             final List<String> newEx = new ArrayList<>();
601             if (fs.getExcludes() != null) {
602                 newEx.addAll(Arrays.asList(fs.getExcludes()));
603             }
604 
605             final String workDirExclude = assemblyWorkPath.substring(fsPath.length() + 1);
606 
607             LOGGER.debug("Adding exclude for assembly working-directory: " + workDirExclude
608                     + "\nFile-Set source directory: " + fsPath);
609 
610             newEx.add(workDirExclude);
611 
612             final List<String> newIn = new ArrayList<>();
613             if (fs.getIncludes() != null) {
614                 for (final String include : fs.getIncludes()) {
615                     if (!include.startsWith(workDirExclude)) {
616                         newIn.add(include);
617                     }
618                 }
619             }
620 
621             final DefaultFileSet dfs = new DefaultFileSet();
622 
623             dfs.setCaseSensitive(fs.isCaseSensitive());
624             dfs.setDirectory(fs.getDirectory());
625             dfs.setExcludes(newEx.toArray(new String[0]));
626             dfs.setFileSelectors(fs.getFileSelectors());
627             dfs.setIncludes(newIn.toArray(new String[0]));
628             dfs.setIncludingEmptyDirectories(fs.isIncludingEmptyDirectories());
629             dfs.setPrefix(fs.getPrefix());
630             dfs.setStreamTransformer(fs.getStreamTransformer());
631 
632             delegate.addFileSet(dfs);
633         } else {
634             delegate.addFileSet(fs);
635         }
636     }
637 
638     private boolean acceptFile(final File inputFile) {
639         if (!Boolean.TRUE.equals(inPublicApi.get())) {
640             if (selectors != null) {
641                 final FileInfo fileInfo = new DefaultFileInfo(inputFile);
642 
643                 for (final FileSelector selector : selectors) {
644                     try {
645                         if (!selector.isSelected(fileInfo)) {
646                             return false;
647                         }
648                     } catch (final IOException e) {
649                         throw new ArchiverException(
650                                 "Error processing file: " + inputFile + " using selector: " + selector, e);
651                     }
652                 }
653             }
654         }
655 
656         return true;
657     }
658 
659     /**
660      * {@inheritDoc}
661      */
662     @Override
663     public void addResource(final PlexusIoResource resource, final String destFileName, final int permissions) {
664         File file = new File(resource.getName()); // zOMG.
665         if (acceptFile(file)) {
666 
667             inPublicApi.set(Boolean.TRUE);
668             try {
669                 delegate.addResource(resource, rootPrefix + destFileName, permissions);
670             } finally {
671                 inPublicApi.set(null);
672             }
673         }
674     }
675 
676     /**
677      * {@inheritDoc}
678      */
679     @Override
680     public void addResources(final PlexusIoResourceCollection resources) {
681         inPublicApi.set(Boolean.TRUE);
682         try {
683             delegate.addResources(resources);
684         } finally {
685             inPublicApi.set(null);
686         }
687     }
688 
689     /**
690      * {@inheritDoc}
691      */
692     @Override
693     public ResourceIterator getResources() {
694         return delegate.getResources();
695     }
696 
697     /**
698      * {@inheritDoc}
699      */
700     @Override
701     public String getDuplicateBehavior() {
702         return delegate.getDuplicateBehavior();
703     }
704 
705     /**
706      * {@inheritDoc}
707      */
708     @Override
709     public void setDuplicateBehavior(final String duplicate) {
710         inPublicApi.set(Boolean.TRUE);
711         try {
712             delegate.setDuplicateBehavior(duplicate);
713         } finally {
714             inPublicApi.set(null);
715         }
716     }
717 
718     /**
719      * {@inheritDoc}
720      */
721     @Override
722     public int getDirectoryMode() {
723         return delegate.getDirectoryMode();
724     }
725 
726     /**
727      * {@inheritDoc}
728      */
729     @Override
730     public void setDirectoryMode(final int mode) {
731         inPublicApi.set(Boolean.TRUE);
732         try {
733             delegate.setDirectoryMode(mode);
734         } finally {
735             inPublicApi.set(null);
736         }
737     }
738 
739     /**
740      * {@inheritDoc}
741      */
742     @Override
743     public int getFileMode() {
744         return delegate.getFileMode();
745     }
746 
747     /**
748      * {@inheritDoc}
749      */
750     @Override
751     public void setFileMode(final int mode) {
752         inPublicApi.set(Boolean.TRUE);
753         try {
754             delegate.setFileMode(mode);
755         } finally {
756             inPublicApi.set(null);
757         }
758     }
759 
760     /**
761      * {@inheritDoc}
762      */
763     @Override
764     public int getOverrideDirectoryMode() {
765         return delegate.getOverrideDirectoryMode();
766     }
767 
768     /**
769      * {@inheritDoc}
770      */
771     @Override
772     public int getOverrideFileMode() {
773         return delegate.getOverrideFileMode();
774     }
775 
776     /**
777      * {@inheritDoc}
778      */
779     @Override
780     public boolean isUseJvmChmod() {
781         return useJvmChmod;
782     }
783 
784     /**
785      * {@inheritDoc}
786      */
787     @Override
788     public void setUseJvmChmod(final boolean useJvmChmod) {
789         this.useJvmChmod = useJvmChmod;
790     }
791 
792     /**
793      * {@inheritDoc}
794      */
795     @Override
796     public boolean isIgnorePermissions() {
797         return delegate.isIgnorePermissions();
798     }
799 
800     /**
801      * {@inheritDoc}
802      */
803     @Override
804     public void setIgnorePermissions(final boolean ignorePermissions) {
805         delegate.setIgnorePermissions(ignorePermissions);
806     }
807 
808     private static final class DefaultFileInfo implements FileInfo {
809 
810         private final File inputFile;
811 
812         DefaultFileInfo(final File inputFile) {
813             this.inputFile = inputFile;
814         }
815 
816         @Override
817         public InputStream getContents() throws IOException {
818             return new FileInputStream(inputFile);
819         }
820 
821         @Override
822         public String getName() {
823             return inputFile.getName();
824         }
825 
826         @Override
827         public boolean isDirectory() {
828             return inputFile.isDirectory();
829         }
830 
831         @Override
832         public boolean isFile() {
833             return inputFile.isFile();
834         }
835 
836         @Override
837         public boolean isSymbolicLink() {
838             return false;
839         }
840     }
841 
842     @Override
843     public void setLastModifiedDate(Date lastModifiedDate) {
844         delegate.setLastModifiedDate(lastModifiedDate);
845     }
846 
847     @Override
848     public Date getLastModifiedDate() {
849         return delegate.getLastModifiedDate();
850     }
851 
852     @Override
853     public void setFilenameComparator(Comparator<String> filenameComparator) {
854         delegate.setFilenameComparator(filenameComparator);
855     }
856 
857     @Override
858     public void configureReproducible(Date outputTimestamp) {
859         delegate.configureReproducible(outputTimestamp);
860     }
861 
862     @Override
863     public void setOverrideUid(int uid) {
864         delegate.setOverrideUid(uid);
865     }
866 
867     @Override
868     public void setOverrideUserName(String userName) {
869         delegate.setOverrideUserName(userName);
870     }
871 
872     @Override
873     public int getOverrideUid() {
874         return delegate.getOverrideUid();
875     }
876 
877     @Override
878     public String getOverrideUserName() {
879         return delegate.getOverrideUserName();
880     }
881 
882     @Override
883     public void setOverrideGid(int gid) {
884         delegate.setOverrideGid(gid);
885     }
886 
887     @Override
888     public void setOverrideGroupName(String groupName) {
889         delegate.setOverrideGroupName(groupName);
890     }
891 
892     @Override
893     public int getOverrideGid() {
894         return delegate.getOverrideGid();
895     }
896 
897     @Override
898     public String getOverrideGroupName() {
899         return delegate.getOverrideGroupName();
900     }
901 
902     @Override
903     public void setLastModifiedTime(FileTime fileTime) {
904         delegate.setLastModifiedTime(fileTime);
905     }
906 
907     @Override
908     public FileTime getLastModifiedTime() {
909         return delegate.getLastModifiedTime();
910     }
911 
912     @Override
913     public void setUmask(int umask) {
914         delegate.setUmask(umask);
915     }
916 
917     @Override
918     public int getUmask() {
919         return delegate.getUmask();
920     }
921 
922     @Override
923     public void configureReproducibleBuild(FileTime fileTime) {
924         delegate.configureReproducibleBuild(fileTime);
925     }
926 }