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