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