View Javadoc
1   package org.apache.maven.plugins.war;
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 java.io.File;
23  import java.io.IOException;
24  import java.nio.file.FileVisitResult;
25  import java.nio.file.Files;
26  import java.nio.file.Path;
27  import java.nio.file.SimpleFileVisitor;
28  import java.nio.file.attribute.BasicFileAttributes;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Collection;
32  import java.util.Collections;
33  import java.util.LinkedHashSet;
34  import java.util.List;
35  
36  import org.apache.maven.archiver.MavenArchiveConfiguration;
37  import org.apache.maven.artifact.factory.ArtifactFactory;
38  import org.apache.maven.execution.MavenSession;
39  import org.apache.maven.model.Resource;
40  import org.apache.maven.plugin.AbstractMojo;
41  import org.apache.maven.plugin.MojoExecutionException;
42  import org.apache.maven.plugin.MojoFailureException;
43  import org.apache.maven.plugin.logging.Log;
44  import org.apache.maven.plugins.annotations.Component;
45  import org.apache.maven.plugins.annotations.Parameter;
46  import org.apache.maven.plugins.war.overlay.OverlayManager;
47  import org.apache.maven.plugins.war.packaging.CopyUserManifestTask;
48  import org.apache.maven.plugins.war.packaging.OverlayPackagingTask;
49  import org.apache.maven.plugins.war.packaging.WarPackagingContext;
50  import org.apache.maven.plugins.war.packaging.WarPackagingTask;
51  import org.apache.maven.plugins.war.packaging.WarProjectPackagingTask;
52  import org.apache.maven.plugins.war.util.WebappStructure;
53  import org.apache.maven.project.MavenProject;
54  import org.apache.maven.shared.filtering.MavenFileFilter;
55  import org.apache.maven.shared.filtering.MavenFilteringException;
56  import org.apache.maven.shared.filtering.MavenResourcesExecution;
57  import org.apache.maven.shared.filtering.MavenResourcesFiltering;
58  import org.apache.maven.shared.utils.StringUtils;
59  import org.apache.maven.shared.utils.io.FileUtils;
60  import org.codehaus.plexus.archiver.Archiver;
61  import org.codehaus.plexus.archiver.jar.JarArchiver;
62  import org.codehaus.plexus.archiver.manager.ArchiverManager;
63  
64  /**
65   * Contains common jobs for WAR mojos.
66   */
67  public abstract class AbstractWarMojo
68      extends AbstractMojo
69  {
70      private static final String META_INF = "META-INF";
71  
72      private static final String WEB_INF = "WEB-INF";
73      /**
74       * Whether or not to fail the build if the <code>web.xml</code> file is missing. Set to <code>false</code> if you
75       * want your WAR built without a <code>web.xml</code> file. This may be useful if you are building an overlay that
76       * has no web.xml file.
77       * <p>
78       * Starting with <b>3.1.0</b>, this property defaults to <code>false</code> if the project depends on the Servlet
79       * 3.0 API or newer.
80       *
81       * @since 2.1-alpha-2
82       */
83      @Parameter
84      protected Boolean failOnMissingWebXml;
85  
86      /**
87       * The Maven project.
88       */
89      @Parameter( defaultValue = "${project}", readonly = true, required = true )
90      private MavenProject project;
91  
92      /**
93       * The directory containing compiled classes.
94       */
95      @Parameter( defaultValue = "${project.build.outputDirectory}", required = true, readonly = true )
96      private File classesDirectory;
97  
98      /**
99       * Whether a JAR file will be created for the classes in the webapp. Using this optional configuration parameter
100      * will make the compiled classes to be archived into a JAR file in <code>/WEB-INF/lib/</code> and the classes
101      * directory will then be excluded from the webapp <code>/WEB-INF/classes/</code>.
102      *
103      * @since 2.0.1
104      */
105     @Parameter( defaultValue = "false" )
106     private boolean archiveClasses;
107 
108     /**
109      * The encoding to use when copying filtered web resources.
110      *
111      * @since 2.3
112      */
113     @Parameter( defaultValue = "${project.build.sourceEncoding}" )
114     private String resourceEncoding;
115 
116     /**
117      * The JAR archiver needed for archiving the classes directory into a JAR file under WEB-INF/lib.
118      */
119     @Component( role = Archiver.class, hint = "jar" )
120     private JarArchiver jarArchiver;
121 
122     /**
123      * The directory where the webapp is built.
124      */
125     @Parameter( defaultValue = "${project.build.directory}/${project.build.finalName}", required = true )
126     private File webappDirectory;
127 
128     /**
129      * Single directory for extra files to include in the WAR. This is where you place your JSP files.
130      */
131     @Parameter( defaultValue = "${basedir}/src/main/webapp", required = true )
132     private File warSourceDirectory;
133 
134     /**
135      * The list of webResources we want to transfer.
136      */
137     @Parameter
138     private Resource[] webResources;
139 
140     /**
141      * Filters (property files) to include during the interpolation of the pom.xml.
142      */
143     @Parameter
144     private List<String> filters;
145 
146     /**
147      * <p>
148      * Set of delimiters for expressions to filter within the resources. These delimiters are specified in the form
149      * 'beginToken*endToken'. If no '*' is given, the delimiter is assumed to be the same for start and end.
150      * </p>
151      * <p>
152      * So, the default filtering delimiters might be specified as:
153      * </p>
154      * 
155      * <pre>
156      * &lt;delimiters&gt;
157      *   &lt;delimiter&gt;${*}&lt;/delimiter&gt;
158      *   &lt;delimiter&gt;@&lt;/delimiter&gt;
159      * &lt;/delimiters&gt;
160      * </pre>
161      * <p>
162      * Since the '@' delimiter is the same on both ends, we don't need to specify '@*@' (though we can).
163      * </p>
164      *
165      * @since 3.0.0
166      */
167     @Parameter
168     private LinkedHashSet<String> delimiters;
169 
170     /**
171      * Use default delimiters in addition to custom delimiters, if any.
172      *
173      * @since 3.0.0
174      */
175     @Parameter( defaultValue = "true" )
176     private boolean useDefaultDelimiters;
177 
178     /**
179      * The path to the web.xml file to use.
180      */
181     @Parameter
182     private File webXml;
183 
184     /**
185      * The path to a configuration file for the servlet container. Note that the file name may be different for
186      * different servlet containers. Apache Tomcat uses a configuration file named context.xml. The file will be copied
187      * to the META-INF directory.
188      */
189     @Parameter
190     private File containerConfigXML;
191 
192     /**
193      * Directory to unpack dependent WARs into if needed.
194      */
195     @Parameter( defaultValue = "${project.build.directory}/war/work", required = true )
196     private File workDirectory;
197 
198     /**
199      * The file name mapping to use when copying libraries and TLDs. If no file mapping is set (default) the files are
200      * copied with their standard names.
201      *
202      * @since 2.1-alpha-1
203      */
204     @Parameter
205     private String outputFileNameMapping;
206 
207     /**
208      */
209     @Component( role = ArtifactFactory.class )
210     private ArtifactFactory artifactFactory;
211 
212     /**
213      * To look up Archiver/UnArchiver implementations.
214      */
215     @Component( role = ArchiverManager.class )
216     private ArchiverManager archiverManager;
217 
218     /**
219      */
220     @Component( role = MavenFileFilter.class, hint = "default" )
221     private MavenFileFilter mavenFileFilter;
222 
223     /**
224      */
225     @Component( role = MavenResourcesFiltering.class, hint = "default" )
226     private MavenResourcesFiltering mavenResourcesFiltering;
227 
228     /**
229      * The comma separated list of tokens to include when copying the content of the warSourceDirectory.
230      */
231     @Parameter( defaultValue = "**" )
232     private String warSourceIncludes;
233 
234     /**
235      * The comma separated list of tokens to exclude when copying the content of the warSourceDirectory.
236      */
237     @Parameter
238     private String warSourceExcludes;
239 
240     /**
241      * The comma separated list of tokens to include when doing a WAR overlay. Default is 
242      * {@link org.apache.maven.plugins.war.Overlay#DEFAULT_INCLUDES}
243      *
244      */
245     @Parameter
246     private String dependentWarIncludes = StringUtils.join( Overlay.DEFAULT_INCLUDES, "," );
247 
248     /**
249      * The comma separated list of tokens to exclude when doing a WAR overlay. Default is 
250      * {@link org.apache.maven.plugins.war.Overlay#DEFAULT_EXCLUDES}
251      *
252      */
253     @Parameter
254     private String dependentWarExcludes = StringUtils.join( Overlay.DEFAULT_EXCLUDES, "," );
255 
256     /**
257      * The overlays to apply. Each &lt;overlay&gt; element may contain:
258      * <ul>
259      * <li>id (defaults to <tt>currentBuild</tt>)</li>
260      * <li>groupId (if this and artifactId are null, then the current project is treated as its own overlay)</li>
261      * <li>artifactId (see above)</li>
262      * <li>classifier</li>
263      * <li>type</li>
264      * <li>includes (a list of string patterns)</li>
265      * <li>excludes (a list of string patterns)</li>
266      * <li>filtered (defaults to false)</li>
267      * <li>skip (defaults to false)</li>
268      * <li>targetPath (defaults to root of webapp structure)</li>
269      * </ul>
270      *
271      * @since 2.1-alpha-1
272      */
273     @Parameter
274     private List<Overlay> overlays = new ArrayList<>();
275 
276     /**
277      * A list of file extensions that should not be filtered. <b>Will be used when filtering webResources and
278      * overlays.</b>
279      *
280      * @since 2.1-alpha-2
281      */
282     @Parameter
283     private List<String> nonFilteredFileExtensions;
284 
285     /**
286      * @since 2.1-alpha-2
287      */
288     @Parameter( defaultValue = "${session}", readonly = true, required = true )
289     private MavenSession session;
290 
291     /**
292      * To filter deployment descriptors. <b>Disabled by default.</b>
293      *
294      * @since 2.1-alpha-2
295      */
296     @Parameter( defaultValue = "false" )
297     private boolean filteringDeploymentDescriptors;
298 
299     /**
300      * To escape interpolated values with Windows path <code>c:\foo\bar</code> will be replaced with
301      * <code>c:\\foo\\bar</code>.
302      *
303      * @since 2.1-alpha-2
304      */
305     @Parameter( defaultValue = "false" )
306     private boolean escapedBackslashesInFilePath;
307 
308     /**
309      * Expression preceded with this String won't be interpolated. <code>\${foo}</code> will be replaced with
310      * <code>${foo}</code>.
311      *
312      * @since 2.1-beta-1
313      */
314     @Parameter
315     protected String escapeString;
316 
317     /**
318      * Indicates if zip archives (jar,zip etc) being added to the war should be compressed again. Compressing again can
319      * result in smaller archive size, but gives noticeably longer execution time.
320      *
321      * @since 2.3
322      */
323     @Parameter( defaultValue = "true" )
324     private boolean recompressZippedFiles;
325 
326     /**
327      * @since 2.4
328      */
329     @Parameter( defaultValue = "false" )
330     private boolean includeEmptyDirectories;
331 
332     /**
333      * Stop searching endToken at the end of line
334      * 
335      * @since 2.4
336      */
337     @Parameter( defaultValue = "false" )
338     private boolean supportMultiLineFiltering;
339 
340     /**
341      * use jvmChmod rather that cli chmod and forking process
342      * 
343      * @since 2.4
344      */
345     @Parameter( defaultValue = "true" )
346     private boolean useJvmChmod;
347 
348     /**
349      * The archive configuration to use. See <a href="http://maven.apache.org/shared/maven-archiver/index.html">Maven
350      * Archiver Reference</a>.
351      */
352     @Parameter
353     private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
354 
355     /**
356      * Timestamp for reproducible output archive entries, either formatted as ISO 8601
357      * <code>yyyy-MM-dd'T'HH:mm:ssXXX</code> or as an int representing seconds since the epoch (like
358      * <a href="https://reproducible-builds.org/docs/source-date-epoch/">SOURCE_DATE_EPOCH</a>).
359      *
360      * @since 3.3.0
361      */
362     @Parameter( defaultValue = "${project.build.outputTimestamp}" )
363     protected String outputTimestamp;
364 
365     /**
366      * Path prefix for resources that will be checked against outdated content.
367      *
368      * @since 3.3.1
369      */
370     @Parameter( defaultValue = "WEB-INF/lib/" )
371     private String outdatedCheckPath;
372 
373     private final Overlay currentProjectOverlay = Overlay.createInstance();
374 
375     /**
376      * @return The current overlay.
377      */
378     public Overlay getCurrentProjectOverlay()
379     {
380         return currentProjectOverlay;
381     }
382 
383     /**
384      * Returns a string array of the excludes to be used when copying the content of the WAR source directory.
385      *
386      * @return an array of tokens to exclude
387      */
388     protected String[] getExcludes()
389     {
390         List<String> excludeList = new ArrayList<>();
391         if ( StringUtils.isNotEmpty( warSourceExcludes ) )
392         {
393             excludeList.addAll( Arrays.asList( StringUtils.split( warSourceExcludes, "," ) ) );
394         }
395 
396         // if webXML is specified, omit the one in the source directory
397         if ( webXml != null && StringUtils.isNotEmpty( webXml.getName() ) )
398         {
399             excludeList.add( "**/" + WEB_INF + "/web.xml" );
400         }
401 
402         // if contextXML is specified, omit the one in the source directory
403         if ( containerConfigXML != null && StringUtils.isNotEmpty( containerConfigXML.getName() ) )
404         {
405             excludeList.add( "**/" + META_INF + "/" + containerConfigXML.getName() );
406         }
407 
408         return excludeList.toArray( new String[excludeList.size()] );
409     }
410 
411     /**
412      * Returns a string array of the includes to be used when assembling/copying the WAR.
413      *
414      * @return an array of tokens to include
415      */
416     protected String[] getIncludes()
417     {
418         return StringUtils.split( StringUtils.defaultString( warSourceIncludes ), "," );
419     }
420 
421     /**
422      * Returns a string array of the excludes to be used when adding dependent WAR as an overlay onto this WAR.
423      *
424      * @return an array of tokens to exclude
425      */
426     protected String[] getDependentWarExcludes()
427     {
428         return StringUtils.split( StringUtils.defaultString( dependentWarExcludes ), "," );
429     }
430 
431     /**
432      * Returns a string array of the includes to be used when adding dependent WARs as an overlay onto this WAR.
433      *
434      * @return an array of tokens to include
435      */
436     protected String[] getDependentWarIncludes()
437     {
438         return StringUtils.split( StringUtils.defaultString( dependentWarIncludes ), "," );
439     }
440 
441     /**
442      * @param webapplicationDirectory The web application directory.
443      * @throws MojoExecutionException In case of failure.
444      * @throws MojoFailureException In case of failure.
445      */
446     public void buildExplodedWebapp( File webapplicationDirectory )
447         throws MojoExecutionException, MojoFailureException
448     {
449         webapplicationDirectory.mkdirs();
450 
451         try
452         {
453             buildWebapp( project, webapplicationDirectory );
454         }
455         catch ( IOException e )
456         {
457             throw new MojoExecutionException( "Could not build webapp", e );
458         }
459     }
460 
461     /**
462      * Builds the webapp for the specified project with the new packaging task thingy.
463      * Classes, libraries and tld files are copied to the <tt>webappDirectory</tt> during this phase.
464      *
465      * @param mavenProject the maven project
466      * @param webapplicationDirectory the target directory
467      * @throws MojoExecutionException if an error occurred while packaging the webapp
468      * @throws MojoFailureException if an unexpected error occurred while packaging the webapp
469      * @throws IOException if an error occurred while copying the files
470      */
471     public void buildWebapp( MavenProject mavenProject, File webapplicationDirectory )
472         throws MojoExecutionException, MojoFailureException, IOException
473     {
474 
475         WebappStructure structure = new WebappStructure( mavenProject.getDependencies() );
476 
477         // CHECKSTYLE_OFF: LineLength
478         final long startTime = System.currentTimeMillis();
479         getLog().info( "Assembling webapp [" + mavenProject.getArtifactId() + "] in [" + webapplicationDirectory + "]" );
480 
481         final OverlayManager overlayManager =
482             new OverlayManager( overlays, mavenProject, getDependentWarIncludes(), getDependentWarExcludes(),
483                                 currentProjectOverlay );
484         // CHECKSTYLE_ON: LineLength
485         List<FileUtils.FilterWrapper> defaultFilterWrappers;
486         try
487         {
488             MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution();
489             mavenResourcesExecution.setEscapeString( escapeString );
490             mavenResourcesExecution.setSupportMultiLineFiltering( supportMultiLineFiltering );
491             mavenResourcesExecution.setMavenProject( mavenProject );
492 
493             // if these are NOT set, just use the defaults, which are '${*}' and '@'.
494             mavenResourcesExecution.setDelimiters( delimiters, useDefaultDelimiters );
495 
496             if ( nonFilteredFileExtensions != null )
497             {
498                 mavenResourcesExecution.setNonFilteredFileExtensions( nonFilteredFileExtensions );
499             }
500             
501             if ( filters == null )
502             {
503                 filters = getProject().getBuild().getFilters();
504             }
505             mavenResourcesExecution.setFilters( filters );
506             mavenResourcesExecution.setEscapedBackslashesInFilePath( escapedBackslashesInFilePath );
507             mavenResourcesExecution.setMavenSession( this.session );
508             mavenResourcesExecution.setEscapeString( this.escapeString );
509             mavenResourcesExecution.setSupportMultiLineFiltering( supportMultiLineFiltering );
510 
511             defaultFilterWrappers = mavenFileFilter.getDefaultFilterWrappers( mavenResourcesExecution );
512 
513         }
514         catch ( MavenFilteringException e )
515         {
516             getLog().error( "fail to build filtering wrappers " + e.getMessage() );
517             throw new MojoExecutionException( e.getMessage(), e );
518         }
519 
520         final WarPackagingContext context =
521             new DefaultWarPackagingContext( webapplicationDirectory, structure, overlayManager, defaultFilterWrappers,
522                                             getNonFilteredFileExtensions(), filteringDeploymentDescriptors,
523                                             this.artifactFactory, resourceEncoding, useJvmChmod, failOnMissingWebXml,
524                                             outputTimestamp );
525 
526         final List<WarPackagingTask> packagingTasks = getPackagingTasks( overlayManager );
527 
528         for ( WarPackagingTask warPackagingTask : packagingTasks )
529         {
530             warPackagingTask.performPackaging( context );
531         }
532 
533         getLog().debug( "Webapp assembled in [" + ( System.currentTimeMillis() - startTime ) + " msecs]" );
534 
535     }
536 
537     /**
538      * Returns a <tt>List</tt> of the {@link org.apache.maven.plugins.war.packaging.WarPackagingTask}
539      * instances to invoke to perform the packaging.
540      *
541      * @param overlayManager the overlay manager
542      * @return the list of packaging tasks
543      * @throws MojoExecutionException if the packaging tasks could not be built
544      */
545     private List<WarPackagingTask> getPackagingTasks( OverlayManager overlayManager )
546         throws MojoExecutionException
547     {
548         final List<WarPackagingTask> packagingTasks = new ArrayList<>();
549 
550         packagingTasks.add( new CopyUserManifestTask() );
551 
552         final List<Overlay> resolvedOverlays = overlayManager.getOverlays();
553         for ( Overlay overlay : resolvedOverlays )
554         {
555             if ( overlay.isCurrentProject() )
556             {
557                 packagingTasks.add( new WarProjectPackagingTask( webResources, webXml, containerConfigXML,
558                                                                  currentProjectOverlay ) );
559             }
560             else
561             {
562                 packagingTasks.add( new OverlayPackagingTask( overlay, currentProjectOverlay ) );
563             }
564         }
565         return packagingTasks;
566     }
567 
568     /**
569      * WarPackagingContext default implementation
570      */
571     private class DefaultWarPackagingContext
572         implements WarPackagingContext
573     {
574         private final ArtifactFactory artifactFactory;
575 
576         private final String resourceEncoding;
577 
578         private final WebappStructure webappStructure;
579 
580         private final File webappDirectory;
581 
582         private final OverlayManager overlayManager;
583 
584         private final List<FileUtils.FilterWrapper> filterWrappers;
585 
586         private List<String> nonFilteredFileExtensions;
587 
588         private boolean filteringDeploymentDescriptors;
589 
590         private boolean useJvmChmod;
591 
592         private final Boolean failOnMissingWebXml;
593 
594         private final Collection<String> outdatedResources;
595 
596         private final String outputTimestamp;
597 
598         /**
599          * @param webappDirectory The web application directory.
600          * @param webappStructure The web app structure.
601          * @param overlayManager The overlay manager.
602          * @param filterWrappers The filter wrappers
603          * @param nonFilteredFileExtensions The non filtered file extensions.
604          * @param filteringDeploymentDescriptors The filtering deployment descriptors.
605          * @param artifactFactory The artifact factory.
606          * @param resourceEncoding The resource encoding.
607          * @param useJvmChmod use Jvm chmod or not.
608          * @param failOnMissingWebXml Flag to check whether we should ignore missing web.xml or not
609          * @param outputTimestamp the output timestamp for reproducible archive creation
610          */
611         DefaultWarPackagingContext( final File webappDirectory, final WebappStructure webappStructure,
612                                            final OverlayManager overlayManager,
613                                            List<FileUtils.FilterWrapper> filterWrappers,
614                                            List<String> nonFilteredFileExtensions,
615                                            boolean filteringDeploymentDescriptors, ArtifactFactory artifactFactory,
616                                            String resourceEncoding, boolean useJvmChmod,
617                                            final Boolean failOnMissingWebXml, String outputTimestamp )
618         {
619             this.webappDirectory = webappDirectory;
620             this.webappStructure = webappStructure;
621             this.overlayManager = overlayManager;
622             this.filterWrappers = filterWrappers;
623             this.artifactFactory = artifactFactory;
624             this.filteringDeploymentDescriptors = filteringDeploymentDescriptors;
625             this.nonFilteredFileExtensions =
626                 nonFilteredFileExtensions == null ? Collections.<String>emptyList() : nonFilteredFileExtensions;
627             this.resourceEncoding = resourceEncoding;
628             // This is kinda stupid but if we loop over the current overlays and we request the path structure
629             // it will register it. This will avoid wrong warning messages in a later phase
630             for ( String overlayId : overlayManager.getOverlayIds() )
631             {
632                 webappStructure.getStructure( overlayId );
633             }
634             this.useJvmChmod = useJvmChmod;
635             this.failOnMissingWebXml = failOnMissingWebXml;
636 
637             if ( !webappDirectory.exists() )
638             {
639                 outdatedResources = Collections.emptyList();
640             }
641             else if ( getWarSourceDirectory().toPath().equals( webappDirectory.toPath() ) )
642             {
643                 getLog().info( "Can't detect outdated resources when running inplace goal" );
644                 outdatedResources = Collections.emptyList();
645             }
646             else
647             {
648                 outdatedResources = new ArrayList<>();
649                 try
650                 {
651                     if ( '\\' == File.separatorChar )
652                     {
653                         outdatedCheckPath = outdatedCheckPath.replace( '/', '\\' );
654                     }
655                     Files.walkFileTree( webappDirectory.toPath(), new SimpleFileVisitor<Path>()
656                     {
657                         @Override
658                         public FileVisitResult visitFile( Path file, BasicFileAttributes attrs )
659                             throws IOException
660                         {
661                             if ( file.toFile().lastModified() < session.getStartTime().getTime() )
662                             {
663                                 // resource older than session build start
664                                 String path = webappDirectory.toPath().relativize( file ).toString();
665                                 if ( path.startsWith( outdatedCheckPath ) )
666                                 {
667                                     outdatedResources.add( path );
668                                 }
669                             }
670                             return super.visitFile( file, attrs );
671                         }
672                     } );
673                 }
674                 catch ( IOException e )
675                 {
676                     getLog().warn( "Can't detect outdated resources", e );
677                 }
678             }
679             this.outputTimestamp = outputTimestamp;
680         }
681 
682         @Override
683         public MavenProject getProject()
684         {
685             return project;
686         }
687 
688         @Override
689         public File getWebappDirectory()
690         {
691             return webappDirectory;
692         }
693 
694         @Override
695         public File getClassesDirectory()
696         {
697             return classesDirectory;
698         }
699 
700         @Override
701         public Log getLog()
702         {
703             return AbstractWarMojo.this.getLog();
704         }
705 
706         @Override
707         public String getOutputFileNameMapping()
708         {
709             return outputFileNameMapping;
710         }
711 
712         @Override
713         public File getWebappSourceDirectory()
714         {
715             return warSourceDirectory;
716         }
717 
718         @Override
719         public String[] getWebappSourceIncludes()
720         {
721             return getIncludes();
722         }
723 
724         @Override
725         public String[] getWebappSourceExcludes()
726         {
727             return getExcludes();
728         }
729 
730         @Override
731         public boolean isWebappSourceIncludeEmptyDirectories()
732         {
733             return includeEmptyDirectories;
734         }
735 
736         @Override
737         public boolean archiveClasses()
738         {
739             return archiveClasses;
740         }
741 
742         @Override
743         public File getOverlaysWorkDirectory()
744         {
745             return workDirectory;
746         }
747 
748         @Override
749         public ArchiverManager getArchiverManager()
750         {
751             return archiverManager;
752         }
753 
754         @Override
755         public MavenArchiveConfiguration getArchive()
756         {
757             return archive;
758         }
759 
760         @Override
761         public JarArchiver getJarArchiver()
762         {
763             return jarArchiver;
764         }
765 
766         @Override
767         public List<String> getFilters()
768         {
769             return filters;
770         }
771 
772         @Override
773         public WebappStructure getWebappStructure()
774         {
775             return webappStructure;
776         }
777 
778         @Override
779         public List<String> getOwnerIds()
780         {
781             return overlayManager.getOverlayIds();
782         }
783 
784         @Override
785         public MavenFileFilter getMavenFileFilter()
786         {
787             return mavenFileFilter;
788         }
789 
790         @Override
791         public List<FileUtils.FilterWrapper> getFilterWrappers()
792         {
793             return filterWrappers;
794         }
795 
796         @Override
797         public boolean isNonFilteredExtension( String fileName )
798         {
799             return !mavenResourcesFiltering.filteredFileExtension( fileName, nonFilteredFileExtensions );
800         }
801 
802         @Override
803         public boolean isFilteringDeploymentDescriptors()
804         {
805             return filteringDeploymentDescriptors;
806         }
807 
808         @Override
809         public ArtifactFactory getArtifactFactory()
810         {
811             return this.artifactFactory;
812         }
813 
814         @Override
815         public MavenSession getSession()
816         {
817             return session;
818         }
819 
820         @Override
821         public String getResourceEncoding()
822         {
823             return resourceEncoding;
824         }
825 
826         @Override
827         public boolean isUseJvmChmod()
828         {
829             return useJvmChmod;
830         }
831 
832         @Override
833         public Boolean isFailOnMissingWebXml()
834         {
835             return failOnMissingWebXml;
836         }
837 
838         @Override
839         public void addResource( String resource )
840         {
841             outdatedResources.remove( resource.replace( '/', File.separatorChar ) );            
842         }
843 
844         @Override
845         public void deleteOutdatedResources()
846         {
847             for ( String resource : outdatedResources )
848             {
849                 getLog().info( "deleting outdated resource " + resource );
850                 new File( getWebappDirectory(), resource ).delete();
851             }
852         }
853 
854         @Override
855         public String getOutputTimestamp()
856         {
857             return outputTimestamp;
858         }
859     }
860 
861     /**
862      * @return The Maven Project.
863      */
864     public MavenProject getProject()
865     {
866         return project;
867     }
868 
869     /**
870      * @param project The project to be set.
871      */
872     public void setProject( MavenProject project )
873     {
874         this.project = project;
875     }
876 
877     /**
878      * @return the classes directory.
879      */
880     public File getClassesDirectory()
881     {
882         return classesDirectory;
883     }
884 
885     /**
886      * @param classesDirectory The classes directory to be set.
887      */
888     public void setClassesDirectory( File classesDirectory )
889     {
890         this.classesDirectory = classesDirectory;
891     }
892 
893     /**
894      * @return {@link #webappDirectory}
895      */
896     public File getWebappDirectory()
897     {
898         return webappDirectory;
899     }
900 
901     /**
902      * @param webappDirectory The web application directory.
903      */
904     public void setWebappDirectory( File webappDirectory )
905     {
906         this.webappDirectory = webappDirectory;
907     }
908 
909     /**
910      * @return {@link #warSourceDirectory}
911      */
912     public File getWarSourceDirectory()
913     {
914         return warSourceDirectory;
915     }
916 
917     /**
918      * @param warSourceDirectory {@link #warSourceDirectory}
919      */
920     public void setWarSourceDirectory( File warSourceDirectory )
921     {
922         this.warSourceDirectory = warSourceDirectory;
923     }
924 
925     /**
926      * @return The {@link #webXml}
927      */
928     public File getWebXml()
929     {
930         return webXml;
931     }
932 
933     /**
934      * @param webXml The {@link #webXml}
935      */
936     public void setWebXml( File webXml )
937     {
938         this.webXml = webXml;
939     }
940 
941     /**
942      * @return {@link #containerConfigXML}
943      */
944     public File getContainerConfigXML()
945     {
946         return containerConfigXML;
947     }
948 
949     /**
950      * @param containerConfigXML {@link #containerConfigXML}
951      */
952     public void setContainerConfigXML( File containerConfigXML )
953     {
954         this.containerConfigXML = containerConfigXML;
955     }
956 
957     /**
958      * @return {@link #outputFileNameMapping}
959      */
960     public String getOutputFileNameMapping()
961     {
962         return outputFileNameMapping;
963     }
964 
965     /**
966      * @param outputFileNameMapping {@link #outputFileNameMapping}
967      */
968     public void setOutputFileNameMapping( String outputFileNameMapping )
969     {
970         this.outputFileNameMapping = outputFileNameMapping;
971     }
972 
973     /**
974      * @return {@link #overlays}
975      */
976     public List<Overlay> getOverlays()
977     {
978         return overlays;
979     }
980 
981     /**
982      * @param overlays {@link #overlays}
983      */
984     public void setOverlays( List<Overlay> overlays )
985     {
986         this.overlays = overlays;
987     }
988 
989     /**
990      * @param overlay add {@link #overlays}.
991      */
992     public void addOverlay( Overlay overlay )
993     {
994         overlays.add( overlay );
995     }
996 
997     /**
998      * @return {@link #archiveClasses}
999      */
1000     public boolean isArchiveClasses()
1001     {
1002         return archiveClasses;
1003     }
1004 
1005     /**
1006      * @param archiveClasses {@link #archiveClasses}
1007      */
1008     public void setArchiveClasses( boolean archiveClasses )
1009     {
1010         this.archiveClasses = archiveClasses;
1011     }
1012 
1013     /**
1014      * @return {@link JarArchiver}
1015      */
1016     public JarArchiver getJarArchiver()
1017     {
1018         return jarArchiver;
1019     }
1020 
1021     /**
1022      * @param jarArchiver {@link JarArchiver}
1023      */
1024     public void setJarArchiver( JarArchiver jarArchiver )
1025     {
1026         this.jarArchiver = jarArchiver;
1027     }
1028 
1029     /**
1030      * @return {@link #webResources}.
1031      */
1032     public Resource[] getWebResources()
1033     {
1034         return webResources;
1035     }
1036 
1037     /**
1038      * @param webResources {@link #webResources}.
1039      */
1040     public void setWebResources( Resource[] webResources )
1041     {
1042         this.webResources = webResources;
1043     }
1044 
1045     /**
1046      * @return {@link #filters}
1047      */
1048     public List<String> getFilters()
1049     {
1050         return filters;
1051     }
1052 
1053     /**
1054      * @param filters {@link #filters}
1055      */
1056     public void setFilters( List<String> filters )
1057     {
1058         this.filters = filters;
1059     }
1060 
1061     /**
1062      * @return {@link #workDirectory}
1063      */
1064     public File getWorkDirectory()
1065     {
1066         return workDirectory;
1067     }
1068 
1069     /**
1070      * @param workDirectory {@link #workDirectory}
1071      */
1072     public void setWorkDirectory( File workDirectory )
1073     {
1074         this.workDirectory = workDirectory;
1075     }
1076 
1077     /**
1078      * @return {@link #warSourceIncludes}
1079      */
1080     public String getWarSourceIncludes()
1081     {
1082         return warSourceIncludes;
1083     }
1084 
1085     /**
1086      * @param warSourceIncludes {@link #warSourceIncludes}
1087      */
1088     public void setWarSourceIncludes( String warSourceIncludes )
1089     {
1090         this.warSourceIncludes = warSourceIncludes;
1091     }
1092 
1093     /**
1094      * @return {@link #warSourceExcludes}
1095      */
1096     public String getWarSourceExcludes()
1097     {
1098         return warSourceExcludes;
1099     }
1100 
1101     /**
1102      * @param warSourceExcludes {@link #warSourceExcludes}
1103      */
1104     public void setWarSourceExcludes( String warSourceExcludes )
1105     {
1106         this.warSourceExcludes = warSourceExcludes;
1107     }
1108 
1109     /**
1110      * @return {@link #archive}
1111      */
1112     public MavenArchiveConfiguration getArchive()
1113     {
1114         return archive;
1115     }
1116 
1117     /**
1118      * @return {@link #nonFilteredFileExtensions}
1119      */
1120     public List<String> getNonFilteredFileExtensions()
1121     {
1122         return nonFilteredFileExtensions;
1123     }
1124 
1125     /**
1126      * @param nonFilteredFileExtensions {@link #nonFilteredFileExtensions}
1127      */
1128     public void setNonFilteredFileExtensions( List<String> nonFilteredFileExtensions )
1129     {
1130         this.nonFilteredFileExtensions = nonFilteredFileExtensions;
1131     }
1132 
1133     /**
1134      * @return {@link #artifactFactory}
1135      */
1136     public ArtifactFactory getArtifactFactory()
1137     {
1138         return this.artifactFactory;
1139     }
1140 
1141     /**
1142      * @param artifactFactory {@link #artifactFactory}
1143      */
1144     public void setArtifactFactory( ArtifactFactory artifactFactory )
1145     {
1146         this.artifactFactory = artifactFactory;
1147     }
1148 
1149     /**
1150      * @return {@link #session}
1151      */
1152     protected MavenSession getSession()
1153     {
1154         return this.session;
1155     }
1156 
1157     /**
1158      * @return {@link #recompressZippedFiles}
1159      */
1160     protected boolean isRecompressZippedFiles()
1161     {
1162         return recompressZippedFiles;
1163     }
1164 
1165     /**
1166      * @return {@link #includeEmptyDirectories}
1167      */
1168     protected boolean isIncludeEmptyDirectories()
1169     {
1170         return includeEmptyDirectories;
1171     }
1172 }