View Javadoc
1   package org.apache.maven.plugin.resources;
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.execution.MavenSession;
23  import org.apache.maven.model.Resource;
24  import org.apache.maven.plugin.AbstractMojo;
25  import org.apache.maven.plugin.MojoExecutionException;
26  import org.apache.maven.plugins.annotations.Component;
27  import org.apache.maven.plugins.annotations.LifecyclePhase;
28  import org.apache.maven.plugins.annotations.Mojo;
29  import org.apache.maven.plugins.annotations.Parameter;
30  import org.apache.maven.project.MavenProject;
31  import org.apache.maven.shared.filtering.MavenFilteringException;
32  import org.apache.maven.shared.filtering.MavenResourcesExecution;
33  import org.apache.maven.shared.filtering.MavenResourcesFiltering;
34  import org.codehaus.plexus.PlexusConstants;
35  import org.codehaus.plexus.PlexusContainer;
36  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
37  import org.codehaus.plexus.context.Context;
38  import org.codehaus.plexus.context.ContextException;
39  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
40  import org.codehaus.plexus.util.ReaderFactory;
41  import org.codehaus.plexus.util.StringUtils;
42  
43  import java.io.File;
44  import java.util.ArrayList;
45  import java.util.Collection;
46  import java.util.Collections;
47  import java.util.LinkedHashSet;
48  import java.util.List;
49  
50  /**
51   * Copy resources for the main source code to the main output directory.
52   * Always uses the project.build.resources element to specify the resources to copy.
53   *
54   * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
55   * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
56   * @author Andreas Hoheneder
57   * @author William Ferguson
58   */
59  @Mojo( name = "resources", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, threadSafe = true )
60  public class ResourcesMojo
61      extends AbstractMojo
62      implements Contextualizable
63  {
64  
65      /**
66       * The character encoding scheme to be applied when filtering resources.
67       */
68      @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
69      protected String encoding;
70  
71      /**
72       * The output directory into which to copy the resources.
73       */
74      @Parameter( defaultValue = "${project.build.outputDirectory}", required = true )
75      private File outputDirectory;
76  
77      /**
78       * The list of resources we want to transfer.
79       */
80      @Parameter( defaultValue = "${project.resources}", required = true, readonly = true )
81      private List<Resource> resources;
82  
83      /**
84       *
85       */
86      @Parameter( defaultValue = "${project}", readonly = true, required = true )
87      protected MavenProject project;
88  
89      /**
90       * The list of additional filter properties files to be used along with System and project
91       * properties, which would be used for the filtering.
92       * <br/>
93       * See also: {@link ResourcesMojo#filters}.
94       *
95       * @since 2.4
96       */
97      @Parameter( defaultValue = "${project.build.filters}", readonly = true )
98      protected List<String> buildFilters;
99  
100     /**
101      * The list of extra filter properties files to be used along with System properties,
102      * project properties, and filter properties files specified in the POM build/filters section,
103      * which should be used for the filtering during the current mojo execution.
104      * <br/>
105      * Normally, these will be configured from a plugin's execution section, to provide a different
106      * set of filters for a particular execution. For instance, starting in Maven 2.2.0, you have the
107      * option of configuring executions with the id's <code>default-resources</code> and
108      * <code>default-testResources</code> to supply different configurations for the two
109      * different types of resources. By supplying <code>extraFilters</code> configurations, you
110      * can separate which filters are used for which type of resource.
111      */
112     @Parameter
113     protected List<String> filters;
114 
115     /**
116      * If false, don't use the filters specified in the build/filters section of the POM when
117      * processing resources in this mojo execution.
118      * <br/>
119      * See also: {@link ResourcesMojo#buildFilters} and {@link ResourcesMojo#filters}
120      *
121      * @since 2.4
122      */
123     @Parameter( defaultValue = "true" )
124     protected boolean useBuildFilters;
125 
126     /**
127      *
128      */
129     @Component( role = MavenResourcesFiltering.class, hint = "default" )
130     protected MavenResourcesFiltering mavenResourcesFiltering;
131 
132     /**
133      *
134      */
135     @Parameter( defaultValue = "${session}", readonly = true, required = true )
136     protected MavenSession session;
137 
138     /**
139      * Expression preceded with the String won't be interpolated
140      * \${foo} will be replaced with ${foo}
141      *
142      * @since 2.3
143      */
144     @Parameter( property = "maven.resources.escapeString" )
145     protected String escapeString;
146 
147     /**
148      * Overwrite existing files even if the destination files are newer.
149      *
150      * @since 2.3
151      */
152     @Parameter( property = "maven.resources.overwrite", defaultValue = "false" )
153     private boolean overwrite;
154 
155     /**
156      * Copy any empty directories included in the Resources.
157      *
158      * @since 2.3
159      */
160     @Parameter( property = "maven.resources.includeEmptyDirs", defaultValue = "false" )
161     protected boolean includeEmptyDirs;
162 
163     /**
164      * Additional file extensions to not apply filtering (already defined are : jpg, jpeg, gif, bmp, png)
165      *
166      * @since 2.3
167      */
168     @Parameter
169     protected List<String> nonFilteredFileExtensions;
170 
171     /**
172      * Whether to escape backslashes and colons in windows-style paths.
173      *
174      * @since 2.4
175      */
176     @Parameter( property = "maven.resources.escapeWindowsPaths", defaultValue = "true" )
177     protected boolean escapeWindowsPaths;
178 
179     /**
180      * <p>
181      * Set of delimiters for expressions to filter within the resources. These delimiters are specified in the
182      * form 'beginToken*endToken'. If no '*' is given, the delimiter is assumed to be the same for start and end.
183      * </p><p>
184      * So, the default filtering delimiters might be specified as:
185      * </p>
186      * <pre>
187      * &lt;delimiters&gt;
188      *   &lt;delimiter&gt;${*}&lt;/delimiter&gt;
189      *   &lt;delimiter&gt;@&lt;/delimiter&gt;
190      * &lt;/delimiters&gt;
191      * </pre>
192      * <p>
193      * Since the '@' delimiter is the same on both ends, we don't need to specify '@*@' (though we can).
194      * </p>
195      *
196      * @since 2.4
197      */
198     @Parameter
199     protected List<String> delimiters;
200 
201     /**
202      * @since 2.4
203      */
204     @Parameter( defaultValue = "true" )
205     protected boolean useDefaultDelimiters;
206 
207     /**
208      * <p>
209      * List of plexus components hint which implements {@link MavenResourcesFiltering#filterResources(MavenResourcesExecution)}.
210      * They will be executed after the resources copying/filtering.
211      * </p>
212      *
213      * @since 2.4
214      */
215     @Parameter
216     private List<String> mavenFilteringHints;
217 
218     /**
219      * @since 2.4
220      */
221     private PlexusContainer plexusContainer;
222 
223     /**
224      * @since 2.4
225      */
226     private List<MavenResourcesFiltering> mavenFilteringComponents = new ArrayList<MavenResourcesFiltering>();
227 
228     /**
229      * stop searching endToken at the end of line
230      *
231      * @since 2.5
232      */
233     @Parameter( property = "maven.resources.supportMultiLineFiltering", defaultValue = "false" )
234     private boolean supportMultiLineFiltering;
235 
236     public void contextualize( Context context )
237         throws ContextException
238     {
239         plexusContainer = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
240     }
241 
242     public void execute()
243         throws MojoExecutionException
244     {
245         try
246         {
247 
248             if ( StringUtils.isEmpty( encoding ) && isFilteringEnabled( getResources() ) )
249             {
250                 getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
251                                    + ", i.e. build is platform dependent!" );
252             }
253 
254             List<String> filters = getCombinedFiltersList();
255 
256             MavenResourcesExecution mavenResourcesExecution =
257                 new MavenResourcesExecution( getResources(), getOutputDirectory(), project, encoding, filters,
258                                              Collections.<String>emptyList(), session );
259 
260             mavenResourcesExecution.setEscapeWindowsPaths( escapeWindowsPaths );
261 
262             // never include project build filters in this call, since we've already accounted for the POM build filters
263             // above, in getCombinedFiltersList().
264             mavenResourcesExecution.setInjectProjectBuildFilters( false );
265 
266             mavenResourcesExecution.setEscapeString( escapeString );
267             mavenResourcesExecution.setOverwrite( overwrite );
268             mavenResourcesExecution.setIncludeEmptyDirs( includeEmptyDirs );
269             mavenResourcesExecution.setSupportMultiLineFiltering( supportMultiLineFiltering );
270 
271             // if these are NOT set, just use the defaults, which are '${*}' and '@'.
272             if ( delimiters != null && !delimiters.isEmpty() )
273             {
274                 LinkedHashSet<String> delims = new LinkedHashSet<String>();
275                 if ( useDefaultDelimiters )
276                 {
277                     delims.addAll( mavenResourcesExecution.getDelimiters() );
278                 }
279 
280                 for ( String delim : delimiters )
281                 {
282                     if ( delim == null )
283                     {
284                         // FIXME: ${filter:*} could also trigger this condition. Need a better long-term solution.
285                         delims.add( "${*}" );
286                     }
287                     else
288                     {
289                         delims.add( delim );
290                     }
291                 }
292 
293                 mavenResourcesExecution.setDelimiters( delims );
294             }
295 
296             if ( nonFilteredFileExtensions != null )
297             {
298                 mavenResourcesExecution.setNonFilteredFileExtensions( nonFilteredFileExtensions );
299             }
300             mavenResourcesFiltering.filterResources( mavenResourcesExecution );
301 
302             executeUserFilterComponents( mavenResourcesExecution );
303         }
304         catch ( MavenFilteringException e )
305         {
306             throw new MojoExecutionException( e.getMessage(), e );
307         }
308     }
309 
310     /**
311      * @since 2.5
312      */
313     protected void executeUserFilterComponents( MavenResourcesExecution mavenResourcesExecution )
314         throws MojoExecutionException, MavenFilteringException
315     {
316 
317         if ( mavenFilteringHints != null )
318         {
319             for ( String hint : mavenFilteringHints )
320             {
321                 try
322                 {
323                     mavenFilteringComponents.add(
324                         (MavenResourcesFiltering) plexusContainer.lookup( MavenResourcesFiltering.class.getName(),
325                                                                           hint ) );
326                 }
327                 catch ( ComponentLookupException e )
328                 {
329                     throw new MojoExecutionException( e.getMessage(), e );
330                 }
331             }
332         }
333         else
334         {
335             getLog().debug( "no use filter components" );
336         }
337 
338         if ( mavenFilteringComponents != null && !mavenFilteringComponents.isEmpty() )
339         {
340             getLog().debug( "execute user filters" );
341             for ( MavenResourcesFiltering filter : mavenFilteringComponents )
342             {
343                 filter.filterResources( mavenResourcesExecution );
344             }
345         }
346     }
347 
348     protected List<String> getCombinedFiltersList()
349     {
350         if ( filters == null || filters.isEmpty() )
351         {
352             return useBuildFilters ? buildFilters : null;
353         }
354         else
355         {
356             List<String> result = new ArrayList<String>();
357 
358             if ( useBuildFilters && buildFilters != null && !buildFilters.isEmpty() )
359             {
360                 result.addAll( buildFilters );
361             }
362 
363             result.addAll( filters );
364 
365             return result;
366         }
367     }
368 
369     /**
370      * Determines whether filtering has been enabled for any resource.
371      *
372      * @param resources The set of resources to check for filtering, may be <code>null</code>.
373      * @return <code>true</code> if at least one resource uses filtering, <code>false</code> otherwise.
374      */
375     private boolean isFilteringEnabled( Collection<Resource> resources )
376     {
377         if ( resources != null )
378         {
379             for ( Resource resource : resources )
380             {
381                 if ( resource.isFiltering() )
382                 {
383                     return true;
384                 }
385             }
386         }
387         return false;
388     }
389 
390     public List<Resource> getResources()
391     {
392         return resources;
393     }
394 
395     public void setResources( List<Resource> resources )
396     {
397         this.resources = resources;
398     }
399 
400     public File getOutputDirectory()
401     {
402         return outputDirectory;
403     }
404 
405     public void setOutputDirectory( File outputDirectory )
406     {
407         this.outputDirectory = outputDirectory;
408     }
409 
410     public boolean isOverwrite()
411     {
412         return overwrite;
413     }
414 
415     public void setOverwrite( boolean overwrite )
416     {
417         this.overwrite = overwrite;
418     }
419 
420     public boolean isIncludeEmptyDirs()
421     {
422         return includeEmptyDirs;
423     }
424 
425     public void setIncludeEmptyDirs( boolean includeEmptyDirs )
426     {
427         this.includeEmptyDirs = includeEmptyDirs;
428     }
429 
430     public List<String> getFilters()
431     {
432         return filters;
433     }
434 
435     public void setFilters( List<String> filters )
436     {
437         this.filters = filters;
438     }
439 
440     public List<String> getDelimiters()
441     {
442         return delimiters;
443     }
444 
445     public void setDelimiters( List<String> delimiters )
446     {
447         this.delimiters = delimiters;
448     }
449 
450     public boolean isUseDefaultDelimiters()
451     {
452         return useDefaultDelimiters;
453     }
454 
455     public void setUseDefaultDelimiters( boolean useDefaultDelimiters )
456     {
457         this.useDefaultDelimiters = useDefaultDelimiters;
458     }
459 
460 }