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