View Javadoc

1   package org.apache.maven.plugin.war.packaging;
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.model.Resource;
23  import org.apache.maven.plugin.MojoExecutionException;
24  import org.apache.maven.plugin.MojoFailureException;
25  import org.apache.maven.plugin.war.Overlay;
26  import org.apache.maven.plugin.war.util.PathSet;
27  import org.apache.maven.shared.filtering.MavenFilteringException;
28  import org.codehaus.plexus.util.DirectoryScanner;
29  import org.codehaus.plexus.util.StringUtils;
30  
31  import java.io.File;
32  import java.io.IOException;
33  import java.util.Iterator;
34  
35  /**
36   * Handles the project own resources, that is:
37   * <ul
38   * <li>The list of web resources, if any</li>
39   * <li>The content of the webapp directory if it exists</li>
40   * <li>The custom deployment descriptor(s), if any</li>
41   * <li>The content of the classes directory if it exists</li>
42   * <li>The dependencies of the project</li>
43   * </ul>
44   *
45   * @author Stephane Nicoll
46   * @version $Id: WarProjectPackagingTask.java 1390132 2012-09-25 21:02:10Z dennisl $
47   */
48  public class WarProjectPackagingTask
49      extends AbstractWarPackagingTask
50  {
51      private final Resource[] webResources;
52  
53      private final File webXml;
54  
55      private final File containerConfigXML;
56  
57      private final String id;
58  
59      private Overlay currentProjectOverlay;
60  
61  
62      public WarProjectPackagingTask( Resource[] webResources, File webXml, File containerConfigXml,
63                                      Overlay currentProjectOverlay )
64      {
65          if ( webResources != null )
66          {
67              this.webResources = webResources;
68          }
69          else
70          {
71              this.webResources = new Resource[0];
72          }
73          this.webXml = webXml;
74          this.containerConfigXML = containerConfigXml;
75          this.currentProjectOverlay = currentProjectOverlay;
76          this.id = currentProjectOverlay.getId();
77      }
78  
79      public void performPackaging( WarPackagingContext context )
80          throws MojoExecutionException, MojoFailureException
81      {
82  
83          context.getLog().info( "Processing war project" );
84          // Prepare the INF directories
85          File webinfDir = new File( context.getWebappDirectory(), WEB_INF_PATH );
86          webinfDir.mkdirs();
87          File metainfDir = new File( context.getWebappDirectory(), META_INF_PATH );
88          metainfDir.mkdirs();
89  
90          handleWebResources( context );
91  
92          handeWebAppSourceDirectory( context );
93  
94          // Debug mode: dump the path set for the current build
95          PathSet pathSet = context.getWebappStructure().getStructure( "currentBuild" );
96          context.getLog().debug( "Dump of the current build pathSet content -->" );
97          for ( Iterator iterator = pathSet.iterator(); iterator.hasNext(); )
98          {
99              context.getLog().debug( "" + iterator.next() );
100         }
101         context.getLog().debug( "-- end of dump --" );
102 
103         handleDeploymentDescriptors( context, webinfDir, metainfDir );
104 
105         handleClassesDirectory( context );
106 
107         handleArtifacts( context );
108     }
109 
110 
111     /**
112      * Handles the web resources.
113      *
114      * @param context the packaging context
115      * @throws MojoExecutionException if a resource could not be copied
116      */
117     protected void handleWebResources( WarPackagingContext context )
118         throws MojoExecutionException
119     {
120         for ( int i = 0; i < webResources.length; i++ )
121         {
122             Resource resource = webResources[i];
123 
124             // MWAR-246
125             if ( resource.getDirectory() == null )
126             {
127                 throw new MojoExecutionException( "The <directory> tag is missing from the <resource> tag." );
128             }
129 
130             if ( !( new File( resource.getDirectory() ) ).isAbsolute() )
131             {
132                 resource.setDirectory( context.getProject().getBasedir() + File.separator + resource.getDirectory() );
133             }
134 
135             // Make sure that the resource directory is not the same as the webappDirectory
136             if ( !resource.getDirectory().equals( context.getWebappDirectory().getPath() ) )
137             {
138 
139                 try
140                 {
141                     copyResources( context, resource );
142                 }
143                 catch ( IOException e )
144                 {
145                     throw new MojoExecutionException( "Could not copy resource [" + resource.getDirectory() + "]", e );
146                 }
147             }
148         }
149     }
150 
151     /**
152      * Handles the webapp sources.
153      *
154      * @param context the packaging context
155      * @throws MojoExecutionException if the sources could not be copied
156      */
157     protected void handeWebAppSourceDirectory( WarPackagingContext context )
158         throws MojoExecutionException
159     {
160         if ( !context.getWebappSourceDirectory().exists() )
161         {
162             context.getLog().debug( "webapp sources directory does not exist - skipping." );
163         }
164         else if ( !context.getWebappSourceDirectory().getAbsolutePath().equals(
165             context.getWebappDirectory().getPath() ) )
166         {
167             context.getLog().info( "Copying webapp resources [" + context.getWebappSourceDirectory() + "]" );
168             final PathSet sources =
169                 getFilesToIncludes( context.getWebappSourceDirectory(), context.getWebappSourceIncludes(),
170                                     context.getWebappSourceExcludes() );
171 
172             try
173             {
174                 copyFiles( id, context, context.getWebappSourceDirectory(), sources, false );
175             }
176             catch ( IOException e )
177             {
178                 throw new MojoExecutionException(
179                     "Could not copy webapp sources [" + context.getWebappDirectory().getAbsolutePath() + "]", e );
180             }
181         }
182     }
183 
184     /**
185      * Handles the webapp artifacts.
186      *
187      * @param context the packaging context
188      * @throws MojoExecutionException if the artifacts could not be packaged
189      */
190     protected void handleArtifacts( WarPackagingContext context )
191         throws MojoExecutionException
192     {
193         ArtifactsPackagingTask task = new ArtifactsPackagingTask( context.getProject().getArtifacts(),
194                                                                   currentProjectOverlay );
195         task.performPackaging( context );
196     }
197 
198     /**
199      * Handles the webapp classes.
200      *
201      * @param context the packaging context
202      * @throws MojoExecutionException if the classes could not be packaged
203      */
204     protected void handleClassesDirectory( WarPackagingContext context )
205         throws MojoExecutionException
206     {
207         ClassesPackagingTask task = new ClassesPackagingTask( currentProjectOverlay );
208         task.performPackaging( context );
209     }
210 
211     /**
212      * Handles the deployment descriptors, if specified. Note that the behavior
213      * here is slightly different since the customized entry always win, even if
214      * an overlay has already packaged a web.xml previously.
215      *
216      * @param context    the packaging context
217      * @param webinfDir  the web-inf directory
218      * @param metainfDir the meta-inf directory
219      * @throws MojoFailureException   if the web.xml is specified but does not exist
220      * @throws MojoExecutionException if an error occurred while copying the descriptors
221      */
222     protected void handleDeploymentDescriptors( WarPackagingContext context, File webinfDir, File metainfDir )
223         throws MojoFailureException, MojoExecutionException
224     {
225         try
226         {
227             if ( webXml != null && StringUtils.isNotEmpty( webXml.getName() ) )
228             {
229                 if ( !webXml.exists() )
230                 {
231                     throw new MojoFailureException( "The specified web.xml file '" + webXml + "' does not exist" );
232                 }
233 
234                 // Making sure that it won't get overlayed
235                 context.getWebappStructure().registerFileForced( id, WEB_INF_PATH + "/web.xml" );
236 
237                 if ( context.isFilteringDeploymentDescriptors() )
238                 {
239                     context.getMavenFileFilter().copyFile( webXml, new File( webinfDir, "web.xml" ), true,
240                                                            context.getFilterWrappers(), getEncoding( webXml ) );
241                 }
242                 else
243                 {
244                     copyFile( context, webXml, new File( webinfDir, "web.xml" ), "WEB-INF/web.xml", true );
245                 }
246             }
247             else
248             {
249                 // the webXml can be the default one
250                 File defaultWebXml = new File( context.getWebappSourceDirectory(), WEB_INF_PATH + "/web.xml" );
251                 // if exists we can filter it
252                 if ( defaultWebXml.exists() && context.isFilteringDeploymentDescriptors() )
253                 {
254                     context.getWebappStructure().registerFile( id, WEB_INF_PATH + "/web.xml" );
255                     context.getMavenFileFilter().copyFile( defaultWebXml, new File( webinfDir, "web.xml" ), true,
256                                                            context.getFilterWrappers(), getEncoding( defaultWebXml ) );
257                 }
258             }
259 
260             if ( containerConfigXML != null && StringUtils.isNotEmpty( containerConfigXML.getName() ) )
261             {
262                 String xmlFileName = containerConfigXML.getName();
263 
264                 context.getWebappStructure().registerFileForced( id, META_INF_PATH + "/" + xmlFileName );
265 
266                 if ( context.isFilteringDeploymentDescriptors() )
267                 {
268                     context.getMavenFileFilter().copyFile( containerConfigXML, new File( metainfDir, xmlFileName ),
269                                                            true, context.getFilterWrappers(),
270                                                            getEncoding( containerConfigXML ) );
271                 }
272                 else
273                 {
274                     copyFile( context, containerConfigXML, new File( metainfDir, xmlFileName ),
275                               "META-INF/" + xmlFileName, true );
276                 }
277             }
278         }
279         catch ( IOException e )
280         {
281             throw new MojoExecutionException( "Failed to copy deployment descriptor", e );
282         }
283         catch ( MavenFilteringException e )
284         {
285             throw new MojoExecutionException( "Failed to copy deployment descriptor", e );
286         }
287     }
288 
289     /**
290      * Copies webapp webResources from the specified directory.
291      *
292      * @param context  the WAR packaging context to use
293      * @param resource the resource to copy
294      * @throws IOException            if an error occurred while copying the resources
295      * @throws MojoExecutionException if an error occurred while retrieving the filter properties
296      */
297     public void copyResources( WarPackagingContext context, Resource resource )
298         throws IOException, MojoExecutionException
299     {
300         if ( !context.getWebappDirectory().exists() )
301         {
302             context.getLog().warn(
303                 "Not copying webapp webResources [" + resource.getDirectory() + "]: webapp directory ["
304                     + context.getWebappDirectory().getAbsolutePath() + "] does not exist!" );
305         }
306 
307         context.getLog().info( "Copying webapp webResources [" + resource.getDirectory() + "] to ["
308             + context.getWebappDirectory().getAbsolutePath() + "]" );
309         String[] fileNames = getFilesToCopy( resource );
310         for ( int i = 0; i < fileNames.length; i++ )
311         {
312             String targetFileName = fileNames[i];
313             if ( resource.getTargetPath() != null )
314             {
315                 //TODO make sure this thing is 100% safe
316                 // MWAR-129 if targetPath is only a dot <targetPath>.</targetPath> or ./
317                 // and the Resource is in a part of the warSourceDirectory the file from sources will override this
318                 // that's we don't have to add the targetPath yep not nice but works
319                 if ( !StringUtils.equals( ".", resource.getTargetPath() )
320                     && !StringUtils.equals( "./", resource.getTargetPath() ) )
321                 {
322                     targetFileName = resource.getTargetPath() + File.separator + targetFileName;
323                 }
324             }
325             if ( resource.isFiltering() && !context.isNonFilteredExtension( fileNames[i] ) )
326             {
327                 copyFilteredFile( id, context, new File( resource.getDirectory(), fileNames[i] ), targetFileName );
328             }
329             else
330             {
331                 copyFile( id, context, new File( resource.getDirectory(), fileNames[i] ), targetFileName );
332             }
333         }
334     }
335 
336 
337     /**
338      * Returns a list of filenames that should be copied
339      * over to the destination directory.
340      *
341      * @param resource the resource to be scanned
342      * @return the array of filenames, relative to the sourceDir
343      */
344     private String[] getFilesToCopy( Resource resource )
345     {
346         DirectoryScanner scanner = new DirectoryScanner();
347         scanner.setBasedir( resource.getDirectory() );
348         if ( resource.getIncludes() != null && !resource.getIncludes().isEmpty() )
349         {
350             scanner.setIncludes(
351                 (String[]) resource.getIncludes().toArray( new String[resource.getIncludes().size()] ) );
352         }
353         else
354         {
355             scanner.setIncludes( DEFAULT_INCLUDES );
356         }
357         if ( resource.getExcludes() != null && !resource.getExcludes().isEmpty() )
358         {
359             scanner.setExcludes(
360                 (String[]) resource.getExcludes().toArray( new String[resource.getExcludes().size()] ) );
361         }
362 
363         scanner.addDefaultExcludes();
364 
365         scanner.scan();
366 
367         return scanner.getIncludedFiles();
368     }
369 }