1 /*
2 * Copyright (C) Christian Schulte, 2005-206
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * o Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * o Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $JOMC: AbstractJomcMojo.java 4876 2014-02-20 11:46:02Z schulte $
29 *
30 */
31 package org.jomc.mojo;
32
33 import java.io.BufferedReader;
34 import java.io.File;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.StringReader;
38 import java.io.StringWriter;
39 import java.net.MalformedURLException;
40 import java.net.SocketTimeoutException;
41 import java.net.URI;
42 import java.net.URISyntaxException;
43 import java.net.URL;
44 import java.net.URLClassLoader;
45 import java.net.URLConnection;
46 import java.util.Collection;
47 import java.util.Date;
48 import java.util.HashSet;
49 import java.util.Iterator;
50 import java.util.List;
51 import java.util.Locale;
52 import java.util.Map;
53 import java.util.Properties;
54 import java.util.Set;
55 import java.util.logging.Level;
56 import javax.xml.bind.JAXBException;
57 import javax.xml.bind.Marshaller;
58 import javax.xml.transform.ErrorListener;
59 import javax.xml.transform.Transformer;
60 import javax.xml.transform.TransformerConfigurationException;
61 import javax.xml.transform.TransformerException;
62 import javax.xml.transform.TransformerFactory;
63 import javax.xml.transform.stream.StreamSource;
64 import org.apache.commons.lang.StringEscapeUtils;
65 import org.apache.commons.lang.StringUtils;
66 import org.apache.maven.artifact.Artifact;
67 import org.apache.maven.artifact.ArtifactUtils;
68 import org.apache.maven.execution.MavenSession;
69 import org.apache.maven.plugin.AbstractMojo;
70 import org.apache.maven.plugin.MojoExecutionException;
71 import org.apache.maven.plugin.MojoFailureException;
72 import org.apache.maven.plugin.descriptor.MojoDescriptor;
73 import org.apache.maven.project.MavenProject;
74 import org.jomc.model.Module;
75 import org.jomc.model.Modules;
76 import org.jomc.model.modlet.DefaultModelProcessor;
77 import org.jomc.model.modlet.DefaultModelProvider;
78 import org.jomc.model.modlet.DefaultModelValidator;
79 import org.jomc.model.modlet.ModelHelper;
80 import org.jomc.modlet.DefaultModelContext;
81 import org.jomc.modlet.DefaultModletProvider;
82 import org.jomc.modlet.Model;
83 import org.jomc.modlet.ModelContext;
84 import org.jomc.modlet.ModelContextFactory;
85 import org.jomc.modlet.ModelException;
86 import org.jomc.modlet.ModelValidationReport;
87 import org.jomc.modlet.Modlet;
88 import org.jomc.modlet.Modlets;
89 import org.jomc.tools.ClassFileProcessor;
90 import org.jomc.tools.JomcTool;
91 import org.jomc.tools.ResourceFileProcessor;
92 import org.jomc.tools.SourceFileProcessor;
93 import org.jomc.tools.modlet.ToolsModelProcessor;
94 import org.jomc.tools.modlet.ToolsModelProvider;
95
96 /**
97 * Base class for executing {@code JomcTool}s.
98 *
99 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
100 * @version $JOMC: AbstractJomcMojo.java 4876 2014-02-20 11:46:02Z schulte $
101 */
102 public abstract class AbstractJomcMojo extends AbstractMojo
103 {
104
105 /**
106 * The encoding to use for reading and writing files.
107 *
108 * @parameter default-value="${project.build.sourceEncoding}" expression="${jomc.sourceEncoding}"
109 */
110 private String sourceEncoding;
111
112 /**
113 * The encoding to use for reading templates.
114 * <p><strong>Deprecated:</strong> As of JOMC 1.3, please use the 'defaultTemplateEncoding' parameter. This
115 * parameter will be removed in version 2.0.</p>
116 *
117 * @parameter expression="${jomc.templateEncoding}"
118 */
119 @Deprecated
120 private String templateEncoding;
121
122 /**
123 * The encoding to use for reading templates.
124 *
125 * @parameter expression="${jomc.defaultTemplateEncoding}"
126 *
127 * @since 1.3
128 */
129 private String defaultTemplateEncoding;
130
131 /**
132 * Location to search for templates in addition to searching the class path of the plugin.
133 * <p>First an attempt is made to parse the location value to an URL. On successful parsing, that URL is used.
134 * Otherwise the location value is interpreted as a directory name relative to the base directory of the project.
135 * If that directory exists, that directory is used. If nothing is found at the given location, a warning message is
136 * logged.</p>
137 *
138 * @parameter expression="${jomc.templateLocation}"
139 * @since 1.2
140 */
141 private String templateLocation;
142
143 /**
144 * The template profile to use when accessing templates.
145 *
146 * @parameter expression="${jomc.templateProfile}"
147 */
148 private String templateProfile;
149
150 /**
151 * The default template profile to use when accessing templates.
152 *
153 * @parameter expression="${jomc.defaultTemplateProfile}"
154 */
155 private String defaultTemplateProfile;
156
157 /**
158 * The location to search for providers.
159 *
160 * @parameter expression="${jomc.providerLocation}"
161 */
162 private String providerLocation;
163
164 /**
165 * The location to search for platform providers.
166 *
167 * @parameter expression="${jomc.platformProviderLocation}"
168 */
169 private String platformProviderLocation;
170
171 /**
172 * The identifier of the model to process.
173 *
174 * @parameter default-value="http://jomc.org/model" expression="${jomc.model}"
175 */
176 private String model;
177
178 /**
179 * The name of the {@code ModelContextFactory} implementation class backing the task.
180 *
181 * @parameter expression="${jomc.modelContextFactoryClassName}"
182 * @since 1.2
183 */
184 private String modelContextFactoryClassName;
185
186 /**
187 * The location to search for modlets.
188 *
189 * @parameter expression="${jomc.modletLocation}"
190 */
191 private String modletLocation;
192
193 /**
194 * The {@code http://jomc.org/modlet} namespace schema system id.
195 *
196 * @parameter expression="${jomc.modletSchemaSystemId}"
197 * @since 1.2
198 */
199 private String modletSchemaSystemId;
200
201 /**
202 * The location to search for modules.
203 *
204 * @parameter expression="${jomc.moduleLocation}"
205 */
206 private String moduleLocation;
207
208 /**
209 * The location to search for transformers.
210 *
211 * @parameter expression="${jomc.transformerLocation}"
212 */
213 private String transformerLocation;
214
215 /**
216 * The indentation string ('\t' for tab).
217 *
218 * @parameter expression="${jomc.indentation}"
219 */
220 private String indentation;
221
222 /**
223 * The line separator ('\r\n' for DOS, '\r' for Mac, '\n' for Unix).
224 *
225 * @parameter expression="${jomc.lineSeparator}"
226 */
227 private String lineSeparator;
228
229 /**
230 * The locale.
231 * <pre>
232 * <locale>
233 * <language>Lowercase two-letter ISO-639 code.</language>
234 * <country>Uppercase two-letter ISO-3166 code.</country>
235 * <variant>Vendor and browser specific code.</variant>
236 * </locale>
237 * </pre>
238 *
239 * @parameter
240 * @since 1.2
241 * @see Locale
242 */
243 private LocaleType locale;
244
245 /**
246 * Controls verbosity of the plugin.
247 *
248 * @parameter expression="${jomc.verbose}" default-value="false"
249 */
250 private boolean verbose;
251
252 /**
253 * Controls processing of source code files.
254 *
255 * @parameter expression="${jomc.sourceProcessing}" default-value="true"
256 */
257 private boolean sourceProcessingEnabled;
258
259 /**
260 * Controls processing of resource files.
261 *
262 * @parameter expression="${jomc.resourceProcessing}" default-value="true"
263 */
264 private boolean resourceProcessingEnabled;
265
266 /**
267 * Controls processing of class files.
268 *
269 * @parameter expression="${jomc.classProcessing}" default-value="true"
270 */
271 private boolean classProcessingEnabled;
272
273 /**
274 * Controls processing of models.
275 *
276 * @parameter expression="${jomc.modelProcessing}" default-value="true"
277 */
278 private boolean modelProcessingEnabled;
279
280 /**
281 * Controls model object class path resolution.
282 *
283 * @parameter expression="${jomc.modelObjectClasspathResolution}" default-value="true"
284 */
285 private boolean modelObjectClasspathResolutionEnabled;
286
287 /**
288 * Name of the module to process.
289 *
290 * @parameter default-value="${project.name}" expression="${jomc.moduleName}"
291 */
292 private String moduleName;
293
294 /**
295 * Name of the test module to process.
296 *
297 * @parameter default-value="${project.name} Tests" expression="${jomc.testModuleName}"
298 */
299 private String testModuleName;
300
301 /**
302 * Directory holding the compiled class files of the project.
303 * <p><strong>Deprecated:</strong> As of JOMC 1.1, please use the 'outputDirectory' parameter. This parameter will
304 * be removed in version 2.0.</p>
305 *
306 * @parameter
307 */
308 @Deprecated
309 private String classesDirectory;
310
311 /**
312 * Directory holding the compiled test class files of the project.
313 * <p><strong>Deprecated:</strong> As of JOMC 1.1, please use the 'testOutputDirectory' parameter. This parameter
314 * will be removed in version 2.0.</p>
315 *
316 * @parameter
317 */
318 @Deprecated
319 private String testClassesDirectory;
320
321 /**
322 * Output directory of the project.
323 *
324 * @parameter default-value="${project.build.outputDirectory}" expression="${jomc.outputDirectory}"
325 * @since 1.1
326 */
327 private String outputDirectory;
328
329 /**
330 * Test output directory of the project.
331 *
332 * @parameter default-value="${project.build.testOutputDirectory}" expression="${jomc.testOutputDirectory}"
333 * @since 1.1
334 */
335 private String testOutputDirectory;
336
337 /**
338 * Directory holding the source files of the project.
339 *
340 * @parameter default-value="${project.build.sourceDirectory}" expression="${jomc.sourceDirectory}"
341 * @since 1.1
342 */
343 private String sourceDirectory;
344
345 /**
346 * Directory holding the test source files of the project.
347 *
348 * @parameter default-value="${project.build.testSourceDirectory}" expression="${jomc.testSourceDirectory}"
349 * @since 1.1
350 */
351 private String testSourceDirectory;
352
353 /**
354 * Directory holding the session related files of the project.
355 *
356 * @parameter default-value="${project.build.directory}/jomc-sessions" expression="${jomc.sessionDirectory}"
357 * @since 1.1
358 */
359 private String sessionDirectory;
360
361 /**
362 * Directory holding the reports of the project.
363 *
364 * @parameter default-value="${project.reporting.outputDirectory}" expression="${jomc.reportOutputDirectory}"
365 * @since 1.1
366 */
367 private String reportOutputDirectory;
368
369 /**
370 * Velocity runtime properties.
371 * <pre>
372 * <velocityProperties>
373 * <velocityProperty>
374 * <key>The name of the property.</key>
375 * <value>The value of the property.</value>
376 * <type>The name of the class of the properties object.</type>
377 * </velocityProperty>
378 * </velocityProperties>
379 * </pre>
380 *
381 * @parameter
382 * @since 1.2
383 */
384 private List<VelocityProperty> velocityProperties;
385
386 /**
387 * Velocity runtime property resources.
388 * <pre>
389 * <velocityPropertyResources>
390 * <velocityPropertyResource>
391 * <location>The location of the properties resource.</location>
392 * <optional>Flag indicating the properties resource is optional.</optional>
393 * <format>The format of the properties resource.</format>
394 * <connectTimeout>Timeout value, in milliseconds.</connectTimeout>
395 * <readTimeout>Timeout value, in milliseconds.</readTimeout>
396 * </velocityPropertyResource>
397 * </velocityPropertyResources>
398 * </pre>
399 * <p>The location value is used to first search the class path of the plugin. If a class path resource is found,
400 * that resource is used. If no class path resource is found, an attempt is made to parse the location value to an
401 * URL. On successful parsing, that URL is used. Otherwise the location value is interpreted as a file name relative
402 * to the base directory of the project. If that file exists, that file is used. If nothing is found at the given
403 * location, depending on the optional flag, a warning message is logged or a build failure is produced.</p>
404 * <p>The optional flag is used to flag the resource optional. When an optional resource is not found, a warning
405 * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false</p>
406 * <p>The format value is used to specify the format of the properties resource. Supported values are {@code plain}
407 * and {@code xml}.<br/><b>Default value is:</b> plain</p>
408 * <p>The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening
409 * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/>
410 * <b>Default value is:</b> 60000</p>
411 * <p>The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource.
412 * A timeout of zero is interpreted as an infinite timeout.<br/>
413 * <b>Default value is:</b> 60000</p>
414 *
415 * @parameter
416 * @since 1.2
417 */
418 private List<VelocityPropertyResource> velocityPropertyResources;
419
420 /**
421 * Template parameters.
422 * <pre>
423 * <templateParameters>
424 * <templateParameter>
425 * <key>The name of the parameter.</key>
426 * <value>The value of the parameter.</value>
427 * <type>The name of the class of the parameter's object.</type>
428 * </templateParameter>
429 * </templateParameters>
430 * </pre>
431 *
432 * @parameter
433 * @since 1.2
434 */
435 private List<TemplateParameter> templateParameters;
436
437 /**
438 * Template parameter resources.
439 * <pre>
440 * <templateParameterResources>
441 * <templateParameterResource>
442 * <location>The location of the properties resource.</location>
443 * <optional>Flag indicating the properties resource is optional.</optional>
444 * <format>The format of the properties resource.</format>
445 * <connectTimeout>Timeout value, in milliseconds.</connectTimeout>
446 * <readTimeout>Timeout value, in milliseconds.</readTimeout>
447 * </templateParameterResource>
448 * </templateParameterResources>
449 * </pre>
450 * <p>The location value is used to first search the class path of the plugin. If a class path resource is found,
451 * that resource is used. If no class path resource is found, an attempt is made to parse the location value to an
452 * URL. On successful parsing, that URL is used. Otherwise the location value is interpreted as a file name relative
453 * to the base directory of the project. If that file exists, that file is used. If nothing is found at the given
454 * location, depending on the optional flag, a warning message is logged or a build failure is produced.</p>
455 * <p>The optional flag is used to flag the resource optional. When an optional resource is not found, a warning
456 * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false</p>
457 * <p>The format value is used to specify the format of the properties resource. Supported values are {@code plain}
458 * and {@code xml}.<br/><b>Default value is:</b> plain</p>
459 * <p>The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening
460 * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/>
461 * <b>Default value is:</b> 60000</p>
462 * <p>The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource.
463 * A timeout of zero is interpreted as an infinite timeout.<br/>
464 * <b>Default value is:</b> 60000</p>
465 *
466 * @parameter
467 * @since 1.2
468 */
469 private List<TemplateParameterResource> templateParameterResources;
470
471 /**
472 * Global transformation parameters.
473 * <pre>
474 * <transformationParameters>
475 * <transformationParameter>
476 * <key>The name of the parameter.</key>
477 * <value>The value of the parameter.</value>
478 * <type>The name of the class of the parameter's object.</type>
479 * </transformationParameter>
480 * </transformationParameters>
481 * </pre>
482 *
483 * @parameter
484 * @since 1.2
485 */
486 private List<TransformationParameter> transformationParameters;
487
488 /**
489 * Global transformation output properties.
490 * <pre>
491 * <transformationOutputProperties>
492 * <transformationOutputProperty>
493 * <key>The name of the property.</key>
494 * <value>The value of the property.</value>
495 * <type>The name of the class of the properties object.</type>
496 * </transformationOutputProperty>
497 * </transformationOutputProperties>
498 * </pre>
499 *
500 * @parameter
501 * @since 1.2
502 */
503 private List<TransformationOutputProperty> transformationOutputProperties;
504
505 /**
506 * Global transformation parameter resources.
507 * <pre>
508 * <transformationParameterResources>
509 * <transformationParameterResource>
510 * <location>The location of the properties resource.</location>
511 * <optional>Flag indicating the properties resource is optional.</optional>
512 * <format>The format of the properties resource.</format>
513 * <connectTimeout>Timeout value, in milliseconds.</connectTimeout>
514 * <readTimeout>Timeout value, in milliseconds.</readTimeout>
515 * </transformationParameterResource>
516 * </transformationParameterResources>
517 * </pre>
518 * <p>The location value is used to first search the class path of the plugin. If a class path resource is found,
519 * that resource is used. If no class path resource is found, an attempt is made to parse the location value to an
520 * URL. On successful parsing, that URL is used. Otherwise the location value is interpreted as a file name relative
521 * to the base directory of the project. If that file exists, that file is used. If nothing is found at the given
522 * location, depending on the optional flag, a warning message is logged or a build failure is produced.</p>
523 * <p>The optional flag is used to flag the resource optional. When an optional resource is not found, a warning
524 * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false</p>
525 * <p>The format value is used to specify the format of the properties resource. Supported values are {@code plain}
526 * and {@code xml}.<br/><b>Default value is:</b> plain</p>
527 * <p>The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening
528 * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/>
529 * <b>Default value is:</b> 60000</p>
530 * <p>The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource.
531 * A timeout of zero is interpreted as an infinite timeout.<br/>
532 * <b>Default value is:</b> 60000</p>
533 *
534 * @parameter
535 * @since 1.2
536 */
537 private List<TransformationParameterResource> transformationParameterResources;
538
539 /**
540 * Class name of the {@code ClassFileProcessor} backing the goal.
541 *
542 * @parameter default-value="org.jomc.tools.ClassFileProcessor" expression="${jomc.classFileProcessorClassName}"
543 * @since 1.2
544 */
545 private String classFileProcessorClassName;
546
547 /**
548 * Class name of the {@code ResourceFileProcessor} backing the goal.
549 *
550 * @parameter default-value="org.jomc.tools.ResourceFileProcessor"
551 * expression="${jomc.resourceFileProcessorClassName}"
552 * @since 1.2
553 */
554 private String resourceFileProcessorClassName;
555
556 /**
557 * Class name of the {@code SourceFileProcessor} backing the goal.
558 *
559 * @parameter default-value="org.jomc.tools.SourceFileProcessor" expression="${jomc.sourceFileProcessorClassName}"
560 * @since 1.2
561 */
562 private String sourceFileProcessorClassName;
563
564 /**
565 * {@code ModelContext} attributes.
566 * <pre>
567 * <modelContextAttributes>
568 * <modelContextAttribute>
569 * <key>The name of the attribute.</key>
570 * <value>The value of the attribute.</value>
571 * <type>The name of the class of the attributes's object.</type>
572 * </modelContextAttribute>
573 * </modelContextAttributes>
574 * </pre>
575 *
576 * @parameter
577 * @since 1.2
578 */
579 private List<ModelContextAttribute> modelContextAttributes;
580
581 /**
582 * Flag controlling JAXP schema validation of model resources.
583 *
584 * @parameter default-value="true" expression="${jomc.modelResourceValidationEnabled}"
585 *
586 * @since 1.2
587 */
588 private boolean modelResourceValidationEnabled;
589
590 /**
591 * Flag controlling JAXP schema validation of modlet resources.
592 *
593 * @parameter default-value="true" expression="${jomc.modletResourceValidationEnabled}"
594 *
595 * @since 1.2
596 */
597 private boolean modletResourceValidationEnabled;
598
599 /**
600 * Flag controlling Java validation.
601 *
602 * @parameter default-value="true" expression="${jomc.javaValidationEnabled}"
603 *
604 * @since 1.4
605 */
606 private boolean javaValidationEnabled;
607
608 /**
609 * Names of modlets to exclude.
610 *
611 * @parameter expression="${jomc.modletExcludes}"
612 *
613 * @since 1.6
614 */
615 private List<String> modletExcludes;
616
617 /**
618 * Names of modlets to include.
619 *
620 * @parameter expression="${jomc.modletIncludes}"
621 *
622 * @since 1.6
623 */
624 private List<String> modletIncludes;
625
626 /**
627 * The Maven project of the instance.
628 *
629 * @parameter expression="${project}"
630 * @required
631 * @readonly
632 */
633 private MavenProject mavenProject;
634
635 /**
636 * List of plugin artifacts.
637 *
638 * @parameter expression="${plugin.artifacts}"
639 * @required
640 * @readonly
641 */
642 private List<Artifact> pluginArtifacts;
643
644 /**
645 * The Maven session of the instance.
646 *
647 * @parameter expression="${session}"
648 * @required
649 * @readonly
650 * @since 1.1
651 */
652 private MavenSession mavenSession;
653
654 /** Creates a new {@code AbstractJomcMojo} instance. */
655 public AbstractJomcMojo()
656 {
657 super();
658 }
659
660 /**
661 * {@inheritDoc}
662 * @see #assertValidParameters()
663 * @see #isExecutionPermitted()
664 * @see #executeTool()
665 */
666 public void execute() throws MojoExecutionException, MojoFailureException
667 {
668 this.assertValidParameters();
669
670 try
671 {
672 this.logSeparator();
673
674 if ( this.isLoggable( Level.INFO ) )
675 {
676 this.log( Level.INFO, Messages.getMessage( "title" ), null );
677 }
678
679 if ( this.isExecutionPermitted() )
680 {
681 this.executeTool();
682 }
683 else if ( this.isLoggable( Level.INFO ) )
684 {
685 this.log( Level.INFO, Messages.getMessage( "executionSuppressed", this.getExecutionStrategy() ), null );
686 }
687 }
688 catch ( final Exception e )
689 {
690 throw new MojoExecutionException( Messages.getMessage( e ), e );
691 }
692 finally
693 {
694 JomcTool.setDefaultTemplateProfile( null );
695 this.logSeparator();
696 }
697 }
698
699 /**
700 * Validates the parameters of the goal.
701 *
702 * @throws MojoFailureException if illegal parameter values are detected.
703 *
704 * @see #assertValidResources(java.util.Collection)
705 * @since 1.2
706 */
707 protected void assertValidParameters() throws MojoFailureException
708 {
709 this.assertValidResources( this.templateParameterResources );
710 this.assertValidResources( this.transformationParameterResources );
711 this.assertValidResources( this.velocityPropertyResources );
712 }
713
714 /**
715 * Validates a given resource collection.
716 *
717 * @param resources The resource collection to validate or {@code null}.
718 *
719 * @throws MojoFailureException if a location property of a given resource holds a {@code null} value or a given
720 * {@code PropertiesResourceType} holds an illegal format.
721 *
722 * @see #assertValidParameters()
723 * @see PropertiesResourceType#isFormatSupported(java.lang.String)
724 * @since 1.2
725 */
726 protected final void assertValidResources( final Collection<? extends ResourceType> resources )
727 throws MojoFailureException
728 {
729 if ( resources != null )
730 {
731 for ( final ResourceType r : resources )
732 {
733 if ( r.getLocation() == null )
734 {
735 throw new MojoFailureException( Messages.getMessage( "mandatoryParameter", "location" ) );
736 }
737
738 if ( r instanceof PropertiesResourceType )
739 {
740 final PropertiesResourceType p = (PropertiesResourceType) r;
741
742 if ( !PropertiesResourceType.isFormatSupported( p.getFormat() ) )
743 {
744 throw new MojoFailureException( Messages.getMessage(
745 "illegalPropertiesFormat", p.getFormat(),
746 StringUtils.join( PropertiesResourceType.getSupportedFormats(), ',' ) ) );
747
748 }
749 }
750 }
751 }
752 }
753
754 /**
755 * Executes this tool.
756 *
757 * @throws Exception if execution of this tool fails.
758 */
759 protected abstract void executeTool() throws Exception;
760
761 /**
762 * Gets the goal of the instance.
763 *
764 * @return The goal of the instance.
765 *
766 * @throws MojoExecutionException if getting the goal of the instance fails.
767 * @since 1.1
768 */
769 protected abstract String getGoal() throws MojoExecutionException;
770
771 /**
772 * Gets the execution strategy of the instance.
773 *
774 * @return The execution strategy of the instance.
775 *
776 * @throws MojoExecutionException if getting the execution strategy of the instance fails.
777 * @since 1.1
778 */
779 protected abstract String getExecutionStrategy() throws MojoExecutionException;
780
781 /**
782 * Gets a flag indicating the current execution is permitted.
783 *
784 * @return {@code true}, if the current execution is permitted; {@code false}, if the current execution is
785 * suppressed.
786 *
787 * @throws MojoExecutionException if getting the flag fails.
788 *
789 * @since 1.1
790 * @see #getGoal()
791 * @see #getExecutionStrategy()
792 */
793 protected boolean isExecutionPermitted() throws MojoExecutionException
794 {
795 try
796 {
797 boolean permitted = true;
798
799 if ( MojoDescriptor.SINGLE_PASS_EXEC_STRATEGY.equals( this.getExecutionStrategy() ) )
800 {
801 final File flagFile =
802 new File( this.getSessionDirectory(),
803 ArtifactUtils.versionlessKey( this.getMavenProject().getArtifact() ).hashCode()
804 + "-" + this.getGoal()
805 + "-" + this.getMavenSession().getStartTime().getTime() + ".flg" );
806
807 if ( !this.getSessionDirectory().exists() && !this.getSessionDirectory().mkdirs() )
808 {
809 throw new MojoExecutionException( Messages.getMessage(
810 "failedCreatingDirectory", this.getSessionDirectory().getAbsolutePath() ) );
811
812 }
813
814 permitted = flagFile.createNewFile();
815 }
816
817 return permitted;
818 }
819 catch ( final IOException e )
820 {
821 throw new MojoExecutionException( Messages.getMessage( e ), e );
822 }
823 }
824
825 /**
826 * Gets the Maven project of the instance.
827 *
828 * @return The Maven project of the instance.
829 *
830 * @throws MojoExecutionException if getting the Maven project of the instance fails.
831 */
832 protected MavenProject getMavenProject() throws MojoExecutionException
833 {
834 return this.mavenProject;
835 }
836
837 /**
838 * Gets the Maven session of the instance.
839 *
840 * @return The Maven session of the instance.
841 *
842 * @throws MojoExecutionException if getting the Maven session of the instance fails.
843 *
844 * @since 1.1
845 */
846 protected MavenSession getMavenSession() throws MojoExecutionException
847 {
848 return this.mavenSession;
849 }
850
851 /**
852 * Gets an absolute {@code File} instance for a given name.
853 * <p>This method constructs a new {@code File} instance using the given name. If the resulting file is not
854 * absolute, the value of the {@code basedir} property of the current Maven project is prepended.</p>
855 *
856 * @param name The name to get an absolute {@code File} instance for.
857 *
858 * @return An absolute {@code File} instance constructed from {@code name}.
859 *
860 * @throws MojoExecutionException if getting an absolute {@code File} instance for {@code name} fails.
861 * @throws NullPointerException if {@code name} is {@code null}.
862 *
863 * @since 1.1
864 */
865 protected File getAbsoluteFile( final String name ) throws MojoExecutionException
866 {
867 if ( name == null )
868 {
869 throw new NullPointerException( "name" );
870 }
871
872 File file = new File( name );
873 if ( !file.isAbsolute() )
874 {
875 file = new File( this.getMavenProject().getBasedir(), name );
876 }
877
878 return file;
879 }
880
881 /**
882 * Gets the directory holding the compiled class files of the project.
883 *
884 * @return The directory holding the compiled class files of the project.
885 *
886 * @throws MojoExecutionException if getting the directory fails.
887 *
888 * @since 1.1
889 */
890 protected File getOutputDirectory() throws MojoExecutionException
891 {
892 if ( this.classesDirectory != null )
893 {
894 if ( this.isLoggable( Level.WARNING ) )
895 {
896 this.log( Level.WARNING, Messages.getMessage(
897 "deprecationWarning", "classesDirectory", "outputDirectory" ), null );
898
899 }
900
901 if ( !this.classesDirectory.equals( this.outputDirectory ) )
902 {
903 if ( this.isLoggable( Level.WARNING ) )
904 {
905 this.log( Level.WARNING, Messages.getMessage( "ignoringParameter", "outputDirectory" ), null );
906 }
907
908 this.outputDirectory = this.classesDirectory;
909 }
910
911 this.classesDirectory = null;
912 }
913
914 final File dir = this.getAbsoluteFile( this.outputDirectory );
915 if ( !dir.exists() && !dir.mkdirs() )
916 {
917 throw new MojoExecutionException( Messages.getMessage( "failedCreatingDirectory", dir.getAbsolutePath() ) );
918 }
919
920 return dir;
921 }
922
923 /**
924 * Gets the directory holding the compiled test class files of the project.
925 *
926 * @return The directory holding the compiled test class files of the project.
927 *
928 * @throws MojoExecutionException if getting the directory fails.
929 *
930 * @since 1.1
931 */
932 protected File getTestOutputDirectory() throws MojoExecutionException
933 {
934 if ( this.testClassesDirectory != null )
935 {
936 if ( this.isLoggable( Level.WARNING ) )
937 {
938 this.log( Level.WARNING, Messages.getMessage(
939 "deprecationWarning", "testClassesDirectory", "testOutputDirectory" ), null );
940
941 }
942
943 if ( !this.testClassesDirectory.equals( this.testOutputDirectory ) )
944 {
945 if ( this.isLoggable( Level.WARNING ) )
946 {
947 this.log( Level.WARNING, Messages.getMessage( "ignoringParameter", "testOutputDirectory" ), null );
948 }
949
950 this.testOutputDirectory = this.testClassesDirectory;
951 }
952
953 this.testClassesDirectory = null;
954 }
955
956 final File dir = this.getAbsoluteFile( this.testOutputDirectory );
957 if ( !dir.exists() && !dir.mkdirs() )
958 {
959 throw new MojoExecutionException( Messages.getMessage( "failedCreatingDirectory", dir.getAbsolutePath() ) );
960 }
961
962 return dir;
963 }
964
965 /**
966 * Gets the directory holding the source files of the project.
967 *
968 * @return The directory holding the source files of the project.
969 *
970 * @throws MojoExecutionException if getting the directory fails.
971 *
972 * @since 1.1
973 */
974 protected File getSourceDirectory() throws MojoExecutionException
975 {
976 return this.getAbsoluteFile( this.sourceDirectory );
977 }
978
979 /**
980 * Gets the directory holding the test source files of the project.
981 *
982 * @return The directory holding the test source files of the project.
983 *
984 * @throws MojoExecutionException if getting the directory fails.
985 *
986 * @since 1.1
987 */
988 protected File getTestSourceDirectory() throws MojoExecutionException
989 {
990 return this.getAbsoluteFile( this.testSourceDirectory );
991 }
992
993 /**
994 * Gets the directory holding the session related files of the project.
995 *
996 * @return The directory holding the session related files of the project.
997 *
998 * @throws MojoExecutionException if getting the directory fails.
999 *
1000 * @since 1.1
1001 */
1002 protected File getSessionDirectory() throws MojoExecutionException
1003 {
1004 return this.getAbsoluteFile( this.sessionDirectory );
1005 }
1006
1007 /**
1008 * Gets the directory holding the reports of the project.
1009 *
1010 * @return The directory holding the reports of the project.
1011 *
1012 * @throws MojoExecutionException if getting the directory fails.
1013 *
1014 * @since 1.1
1015 */
1016 protected File getReportOutputDirectory() throws MojoExecutionException
1017 {
1018 return this.getAbsoluteFile( this.reportOutputDirectory );
1019 }
1020
1021 /**
1022 * Gets the project's runtime class loader of the instance.
1023 *
1024 * @return The project's runtime class loader of the instance.
1025 *
1026 * @throws MojoExecutionException if getting the class loader fails.
1027 */
1028 protected ClassLoader getMainClassLoader() throws MojoExecutionException
1029 {
1030 try
1031 {
1032 final Set<String> mainClasspathElements = this.getMainClasspathElements();
1033 final Set<URI> uris = new HashSet<URI>( mainClasspathElements.size() );
1034
1035 for ( final String element : mainClasspathElements )
1036 {
1037 final URI uri = new File( element ).toURI();
1038 if ( !uris.contains( uri ) )
1039 {
1040 uris.add( uri );
1041 }
1042 }
1043
1044 if ( this.isLoggable( Level.FINEST ) )
1045 {
1046 this.log( Level.FINEST, Messages.getMessage( "mainClasspathInfo" ), null );
1047 }
1048
1049 int i = 0;
1050 final URL[] urls = new URL[ uris.size() ];
1051 for ( final URI uri : uris )
1052 {
1053 urls[i++] = uri.toURL();
1054
1055 if ( this.isLoggable( Level.FINEST ) )
1056 {
1057 this.log( Level.FINEST, "\t" + urls[i - 1].toExternalForm(), null );
1058 }
1059 }
1060
1061 return new URLClassLoader( urls, Thread.currentThread().getContextClassLoader() );
1062 }
1063 catch ( final IOException e )
1064 {
1065 throw new MojoExecutionException( Messages.getMessage( e ), e );
1066 }
1067 }
1068
1069 /**
1070 * Gets the project's test class loader of the instance.
1071 *
1072 * @return The project's test class loader of the instance.
1073 *
1074 * @throws MojoExecutionException if getting the class loader fails.
1075 */
1076 protected ClassLoader getTestClassLoader() throws MojoExecutionException
1077 {
1078 try
1079 {
1080 final Set<String> testClasspathElements = this.getTestClasspathElements();
1081 final Set<URI> uris = new HashSet<URI>( testClasspathElements.size() );
1082
1083 for ( final String element : testClasspathElements )
1084 {
1085 final URI uri = new File( element ).toURI();
1086 if ( !uris.contains( uri ) )
1087 {
1088 uris.add( uri );
1089 }
1090 }
1091
1092 if ( this.isLoggable( Level.FINEST ) )
1093 {
1094 this.log( Level.FINEST, Messages.getMessage( "testClasspathInfo" ), null );
1095 }
1096
1097 int i = 0;
1098 final URL[] urls = new URL[ uris.size() ];
1099 for ( final URI uri : uris )
1100 {
1101 urls[i++] = uri.toURL();
1102
1103 if ( this.isLoggable( Level.FINEST ) )
1104 {
1105 this.log( Level.FINEST, "\t" + urls[i - 1].toExternalForm(), null );
1106 }
1107 }
1108
1109 return new URLClassLoader( urls, Thread.currentThread().getContextClassLoader() );
1110 }
1111 catch ( final IOException e )
1112 {
1113 throw new MojoExecutionException( Messages.getMessage( e ), e );
1114 }
1115 }
1116
1117 /**
1118 * Gets the project's runtime class path elements.
1119 *
1120 * @return A set of class path element strings.
1121 *
1122 * @throws MojoExecutionException if getting the class path elements fails.
1123 */
1124 protected Set<String> getMainClasspathElements() throws MojoExecutionException
1125 {
1126 final List<?> runtimeArtifacts = this.getMavenProject().getRuntimeArtifacts();
1127 final List<?> compileArtifacts = this.getMavenProject().getCompileArtifacts();
1128 final Set<String> elements = new HashSet<String>( runtimeArtifacts.size() + compileArtifacts.size() + 1 );
1129 elements.add( this.getOutputDirectory().getAbsolutePath() );
1130
1131 for ( final Iterator<?> it = runtimeArtifacts.iterator(); it.hasNext(); )
1132 {
1133 final Artifact a = (Artifact) it.next();
1134 final Artifact pluginArtifact = this.getPluginArtifact( a );
1135
1136 if ( a.getFile() == null )
1137 {
1138 if ( this.isLoggable( Level.WARNING ) )
1139 {
1140 this.log( Level.WARNING, Messages.getMessage( "ignoringArtifact", a.toString() ), null );
1141 }
1142
1143 continue;
1144 }
1145
1146 if ( pluginArtifact != null )
1147 {
1148 if ( this.isLoggable( Level.FINER ) )
1149 {
1150 this.log( Level.FINER, Messages.getMessage(
1151 "ignoringPluginArtifact", a.toString(), pluginArtifact.toString() ), null );
1152
1153 }
1154
1155 continue;
1156 }
1157
1158 final String element = a.getFile().getAbsolutePath();
1159 elements.add( element );
1160 }
1161
1162 for ( final Iterator<?> it = compileArtifacts.iterator(); it.hasNext(); )
1163 {
1164 final Artifact a = (Artifact) it.next();
1165 final Artifact pluginArtifact = this.getPluginArtifact( a );
1166
1167 if ( a.getFile() == null )
1168 {
1169 if ( this.isLoggable( Level.WARNING ) )
1170 {
1171 this.log( Level.WARNING, Messages.getMessage( "ignoringArtifact", a.toString() ), null );
1172 }
1173
1174 continue;
1175 }
1176
1177 if ( pluginArtifact != null )
1178 {
1179 if ( this.isLoggable( Level.FINER ) )
1180 {
1181 this.log( Level.FINER, Messages.getMessage(
1182 "ignoringPluginArtifact", a.toString(), pluginArtifact.toString() ), null );
1183
1184 }
1185
1186 continue;
1187 }
1188
1189 final String element = a.getFile().getAbsolutePath();
1190 elements.add( element );
1191 }
1192
1193 return elements;
1194 }
1195
1196 /**
1197 * Gets the project's test class path elements.
1198 *
1199 * @return A set of class path element strings.
1200 *
1201 * @throws MojoExecutionException if getting the class path elements fails.
1202 */
1203 protected Set<String> getTestClasspathElements() throws MojoExecutionException
1204 {
1205 final List<?> testArtifacts = this.getMavenProject().getTestArtifacts();
1206 final Set<String> elements = new HashSet<String>( testArtifacts.size() + 2 );
1207 elements.add( this.getOutputDirectory().getAbsolutePath() );
1208 elements.add( this.getTestOutputDirectory().getAbsolutePath() );
1209
1210 for ( final Iterator<?> it = testArtifacts.iterator(); it.hasNext(); )
1211 {
1212 final Artifact a = (Artifact) it.next();
1213 final Artifact pluginArtifact = this.getPluginArtifact( a );
1214
1215 if ( a.getFile() == null )
1216 {
1217 if ( this.isLoggable( Level.WARNING ) )
1218 {
1219 this.log( Level.WARNING, Messages.getMessage( "ignoringArtifact", a.toString() ), null );
1220 }
1221
1222 continue;
1223 }
1224
1225 if ( pluginArtifact != null )
1226 {
1227 if ( this.isLoggable( Level.FINER ) )
1228 {
1229 this.log( Level.FINER, Messages.getMessage(
1230 "ignoringPluginArtifact", a.toString(), pluginArtifact.toString() ), null );
1231
1232 }
1233
1234 continue;
1235 }
1236
1237 final String element = a.getFile().getAbsolutePath();
1238 elements.add( element );
1239 }
1240
1241 return elements;
1242 }
1243
1244 /**
1245 * Gets a flag indicating verbose output is enabled.
1246 *
1247 * @return {@code true}, if verbose output is enabled; {@code false}, if information messages are suppressed.
1248 *
1249 * @throws MojoExecutionException if getting the flag fails.
1250 *
1251 * @since 1.1
1252 */
1253 protected final boolean isVerbose() throws MojoExecutionException
1254 {
1255 return this.verbose;
1256 }
1257
1258 /**
1259 * Sets the flag indicating verbose output is enabled.
1260 *
1261 * @param value {@code true}, to enable verbose output; {@code false}, to suppress information messages.
1262 *
1263 * @throws MojoExecutionException if setting the flag fails.
1264 *
1265 * @since 1.1
1266 */
1267 protected final void setVerbose( final boolean value ) throws MojoExecutionException
1268 {
1269 this.verbose = value;
1270 }
1271
1272 /**
1273 * Gets a flag indicating the processing of sources is enabled.
1274 *
1275 * @return {@code true}, if processing of sources is enabled; {@code false}, else.
1276 *
1277 * @throws MojoExecutionException if getting the flag fails.
1278 */
1279 protected final boolean isSourceProcessingEnabled() throws MojoExecutionException
1280 {
1281 return this.sourceProcessingEnabled;
1282 }
1283
1284 /**
1285 * Sets the flag indicating the processing of sources is enabled.
1286 *
1287 * @param value {@code true}, to enable processing of sources; {@code false}, to disable processing of sources.
1288 *
1289 * @throws MojoExecutionException if setting the flag fails.
1290 *
1291 * @since 1.1
1292 */
1293 protected final void setSourceProcessingEnabled( final boolean value ) throws MojoExecutionException
1294 {
1295 this.sourceProcessingEnabled = value;
1296 }
1297
1298 /**
1299 * Gets a flag indicating the processing of resources is enabled.
1300 *
1301 * @return {@code true}, if processing of resources is enabled; {@code false}, else.
1302 *
1303 * @throws MojoExecutionException if getting the flag fails.
1304 */
1305 protected final boolean isResourceProcessingEnabled() throws MojoExecutionException
1306 {
1307 return this.resourceProcessingEnabled;
1308 }
1309
1310 /**
1311 * Sets the flag indicating the processing of resources is enabled.
1312 *
1313 * @param value {@code true}, to enable processing of resources; {@code false}, to disable processing of resources.
1314 *
1315 * @throws MojoExecutionException if setting the flag fails.
1316 *
1317 * @since 1.1
1318 */
1319 protected final void setResourceProcessingEnabled( final boolean value ) throws MojoExecutionException
1320 {
1321 this.resourceProcessingEnabled = value;
1322 }
1323
1324 /**
1325 * Gets a flag indicating the processing of classes is enabled.
1326 *
1327 * @return {@code true}, if processing of classes is enabled; {@code false}, else.
1328 *
1329 * @throws MojoExecutionException if getting the flag fails.
1330 */
1331 protected final boolean isClassProcessingEnabled() throws MojoExecutionException
1332 {
1333 return this.classProcessingEnabled;
1334 }
1335
1336 /**
1337 * Sets the flag indicating the processing of classes is enabled.
1338 *
1339 * @param value {@code true}, to enable processing of classes; {@code false}, to disable processing of classes.
1340 *
1341 * @throws MojoExecutionException if setting the flag fails.
1342 *
1343 * @since 1.1
1344 */
1345 protected final void setClassProcessingEnabled( final boolean value ) throws MojoExecutionException
1346 {
1347 this.classProcessingEnabled = value;
1348 }
1349
1350 /**
1351 * Gets a flag indicating the processing of models is enabled.
1352 *
1353 * @return {@code true}, if processing of models is enabled; {@code false}, else.
1354 *
1355 * @throws MojoExecutionException if getting the flag fails.
1356 */
1357 protected final boolean isModelProcessingEnabled() throws MojoExecutionException
1358 {
1359 return this.modelProcessingEnabled;
1360 }
1361
1362 /**
1363 * Sets the flag indicating the processing of models is enabled.
1364 *
1365 * @param value {@code true}, to enable processing of models; {@code false}, to disable processing of models.
1366 *
1367 * @throws MojoExecutionException if setting the flag fails.
1368 *
1369 * @since 1.1
1370 */
1371 protected final void setModelProcessingEnabled( final boolean value ) throws MojoExecutionException
1372 {
1373 this.modelProcessingEnabled = value;
1374 }
1375
1376 /**
1377 * Gets a flag indicating model object class path resolution is enabled.
1378 *
1379 * @return {@code true}, if model object class path resolution is enabled; {@code false}, else.
1380 *
1381 * @throws MojoExecutionException if getting the flag fails.
1382 */
1383 protected final boolean isModelObjectClasspathResolutionEnabled() throws MojoExecutionException
1384 {
1385 return this.modelObjectClasspathResolutionEnabled;
1386 }
1387
1388 /**
1389 * Sets the flag indicating model object class path resolution is enabled.
1390 *
1391 * @param value {@code true}, to enable model object class path resolution; {@code false}, to disable model object
1392 * class path resolution.
1393 *
1394 * @throws MojoExecutionException if setting the flag fails.
1395 *
1396 * @since 1.1
1397 */
1398 protected final void setModelObjectClasspathResolutionEnabled( final boolean value ) throws MojoExecutionException
1399 {
1400 this.modelObjectClasspathResolutionEnabled = value;
1401 }
1402
1403 /**
1404 * Gets the identifier of the model to process.
1405 *
1406 * @return The identifier of the model to process.
1407 *
1408 * @throws MojoExecutionException if getting the identifier fails.
1409 */
1410 protected String getModel() throws MojoExecutionException
1411 {
1412 return this.model;
1413 }
1414
1415 /**
1416 * Gets the name of the module to process.
1417 *
1418 * @return The name of the module to process.
1419 *
1420 * @throws MojoExecutionException if getting the name of the module fails.
1421 */
1422 protected String getModuleName() throws MojoExecutionException
1423 {
1424 return this.moduleName;
1425 }
1426
1427 /**
1428 * Gets the name of the test module to process.
1429 *
1430 * @return The name of the test module to process.
1431 *
1432 * @throws MojoExecutionException if getting the name of the test module fails.
1433 */
1434 protected String getTestModuleName() throws MojoExecutionException
1435 {
1436 return this.testModuleName;
1437 }
1438
1439 /**
1440 * Gets the model to process.
1441 *
1442 * @param context The model context to get the model to process with.
1443 *
1444 * @return The model to process.
1445 *
1446 * @throws NullPointerException if {@code context} is {@code null}.
1447 * @throws MojoExecutionException if getting the model fails.
1448 */
1449 protected Model getModel( final ModelContext context ) throws MojoExecutionException
1450 {
1451 if ( context == null )
1452 {
1453 throw new NullPointerException( "context" );
1454 }
1455
1456 try
1457 {
1458 Model m = context.findModel( this.getModel() );
1459 final Modules modules = ModelHelper.getModules( m );
1460
1461 if ( modules != null && this.isModelObjectClasspathResolutionEnabled() )
1462 {
1463 final Module classpathModule =
1464 modules.getClasspathModule( Modules.getDefaultClasspathModuleName(), context.getClassLoader() );
1465
1466 if ( classpathModule != null )
1467 {
1468 modules.getModule().add( classpathModule );
1469 }
1470 }
1471
1472 if ( this.isModelProcessingEnabled() )
1473 {
1474 m = context.processModel( m );
1475 }
1476
1477 return m;
1478 }
1479 catch ( final ModelException e )
1480 {
1481 throw new MojoExecutionException( Messages.getMessage( e ), e );
1482 }
1483 }
1484
1485 /**
1486 * Creates a new model context instance for a given class loader.
1487 *
1488 * @param classLoader The class loader to use for creating the context.
1489 *
1490 * @return A new model context instance for {@code classLoader}.
1491 *
1492 * @throws MojoExecutionException if creating the model context fails.
1493 *
1494 * @see #setupModelContext(org.jomc.modlet.ModelContext)
1495 */
1496 protected ModelContext createModelContext( final ClassLoader classLoader ) throws MojoExecutionException
1497 {
1498 final ModelContextFactory modelContextFactory;
1499 if ( this.modelContextFactoryClassName != null )
1500 {
1501 modelContextFactory = ModelContextFactory.newInstance( this.modelContextFactoryClassName );
1502 }
1503 else
1504 {
1505 modelContextFactory = ModelContextFactory.newInstance();
1506 }
1507
1508 final ModelContext context = modelContextFactory.newModelContext( classLoader );
1509 this.setupModelContext( context );
1510
1511 return context;
1512 }
1513
1514 /**
1515 * Creates a new tool instance for processing source files.
1516 *
1517 * @param context The context of the tool.
1518 *
1519 * @return A new tool instance for processing source files.
1520 *
1521 * @throws NullPointerException if {@code context} is {@code null}.
1522 * @throws MojoExecutionException if creating a new tool instance fails.
1523 *
1524 * @see #createJomcTool(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class)
1525 */
1526 protected SourceFileProcessor createSourceFileProcessor( final ModelContext context ) throws MojoExecutionException
1527 {
1528 if ( context == null )
1529 {
1530 throw new NullPointerException( "context" );
1531 }
1532
1533 return this.createJomcTool( context, this.sourceFileProcessorClassName, SourceFileProcessor.class );
1534 }
1535
1536 /**
1537 * Creates a new tool instance for processing resource files.
1538 *
1539 * @param context The context of the tool.
1540 *
1541 * @return A new tool instance for processing resource files.
1542 *
1543 * @throws NullPointerException if {@code context} is {@code null}.
1544 * @throws MojoExecutionException if creating a new tool instance fails.
1545 *
1546 * @see #createJomcTool(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class)
1547 */
1548 protected ResourceFileProcessor createResourceFileProcessor( final ModelContext context )
1549 throws MojoExecutionException
1550 {
1551 if ( context == null )
1552 {
1553 throw new NullPointerException( "context" );
1554 }
1555
1556 return this.createJomcTool( context, this.resourceFileProcessorClassName, ResourceFileProcessor.class );
1557 }
1558
1559 /**
1560 * Creates a new tool instance for processing class files.
1561 *
1562 * @param context The context of the tool.
1563 *
1564 * @return A new tool instance for processing class files.
1565 *
1566 * @throws NullPointerException if {@code context} is {@code null}.
1567 * @throws MojoExecutionException if creating a new tool instance fails.
1568 *
1569 * @see #createJomcTool(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class)
1570 */
1571 protected ClassFileProcessor createClassFileProcessor( final ModelContext context ) throws MojoExecutionException
1572 {
1573 if ( context == null )
1574 {
1575 throw new NullPointerException( "context" );
1576 }
1577
1578 return this.createJomcTool( context, this.classFileProcessorClassName, ClassFileProcessor.class );
1579 }
1580
1581 /**
1582 * Creates a new {@code JomcTool} object for a given class name and type.
1583 *
1584 * @param context The context of the tool.
1585 * @param className The name of the class to create an object of.
1586 * @param type The class of the type of object to create.
1587 * @param <T> The type of the object to create.
1588 *
1589 * @return A new instance of the class with name {@code className}.
1590 *
1591 * @throws NullPointerException if {@code context}, {@code className} or {@code type} is {@code null}.
1592 * @throws MojoExecutionException if creating a new {@code JomcTool} object fails.
1593 *
1594 * @see #createObject(java.lang.String, java.lang.Class)
1595 * @see #setupJomcTool(org.jomc.modlet.ModelContext, org.jomc.tools.JomcTool)
1596 *
1597 * @since 1.2
1598 */
1599 protected <T extends JomcTool> T createJomcTool( final ModelContext context, final String className,
1600 final Class<T> type ) throws MojoExecutionException
1601 {
1602 if ( context == null )
1603 {
1604 throw new NullPointerException( "context" );
1605 }
1606 if ( className == null )
1607 {
1608 throw new NullPointerException( "className" );
1609 }
1610 if ( type == null )
1611 {
1612 throw new NullPointerException( "type" );
1613 }
1614
1615 final T tool = this.createObject( className, type );
1616 this.setupJomcTool( context, tool );
1617 return tool;
1618 }
1619
1620 /**
1621 * Creates a new object for a given class name and type.
1622 *
1623 * @param className The name of the class to create an object of.
1624 * @param type The class of the type of object to create.
1625 * @param <T> The type of the object to create.
1626 *
1627 * @return A new instance of the class with name {@code className}.
1628 *
1629 * @throws NullPointerException if {@code className} or {@code type} is {@code null}.
1630 * @throws MojoExecutionException if creating a new object fails.
1631 *
1632 * @since 1.2
1633 */
1634 protected <T> T createObject( final String className, final Class<T> type ) throws MojoExecutionException
1635 {
1636 if ( className == null )
1637 {
1638 throw new NullPointerException( "className" );
1639 }
1640 if ( type == null )
1641 {
1642 throw new NullPointerException( "type" );
1643 }
1644
1645 try
1646 {
1647 return Class.forName( className ).asSubclass( type ).newInstance();
1648 }
1649 catch ( final InstantiationException e )
1650 {
1651 throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1652 }
1653 catch ( final IllegalAccessException e )
1654 {
1655 throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1656 }
1657 catch ( final ClassNotFoundException e )
1658 {
1659 throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1660 }
1661 catch ( final ClassCastException e )
1662 {
1663 throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1664 }
1665 }
1666
1667 /**
1668 * Creates an {@code URL} for a given resource location.
1669 * <p>This method first searches the class path of the plugin for a single resource matching {@code location}. If
1670 * such a resource is found, the URL of that resource is returned. If no such resource is found, an attempt is made
1671 * to parse the given location to an URL. On successful parsing, that URL is returned. Failing that, the given
1672 * location is interpreted as a file name relative to the project's base directory. If that file is found, the URL
1673 * of that file is returned. Otherwise {@code null} is returned.</p>
1674 *
1675 * @param location The location to create an {@code URL} from.
1676 *
1677 * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and
1678 * {@code location} points to a non-existent resource.
1679 *
1680 * @throws NullPointerException if {@code location} is {@code null}.
1681 * @throws MojoExecutionException if creating an URL fails.
1682 *
1683 * @since 1.2
1684 */
1685 protected URL getResource( final String location ) throws MojoExecutionException
1686 {
1687 if ( location == null )
1688 {
1689 throw new NullPointerException( "location" );
1690 }
1691
1692 try
1693 {
1694 String absolute = location;
1695 if ( !absolute.startsWith( "/" ) )
1696 {
1697 absolute = "/" + location;
1698 }
1699
1700 URL resource = this.getClass().getResource( absolute );
1701 if ( resource == null )
1702 {
1703 try
1704 {
1705 resource = new URL( location );
1706 }
1707 catch ( final MalformedURLException e )
1708 {
1709 if ( this.isLoggable( Level.FINEST ) )
1710 {
1711 this.log( Level.FINEST, Messages.getMessage( e ), e );
1712 }
1713
1714 resource = null;
1715 }
1716 }
1717
1718 if ( resource == null )
1719 {
1720 final File f = this.getAbsoluteFile( location );
1721
1722 if ( f.isFile() )
1723 {
1724 resource = f.toURI().toURL();
1725 }
1726 }
1727
1728 return resource;
1729 }
1730 catch ( final MalformedURLException e )
1731 {
1732 String m = Messages.getMessage( e );
1733 m = m == null ? "" : " " + m;
1734
1735 throw new MojoExecutionException( Messages.getMessage( "malformedLocation", location, m ), e );
1736 }
1737 }
1738
1739 /**
1740 * Creates an {@code URL} for a given directory location.
1741 * <p>This method first attempts to parse the given location to an URL. On successful parsing, that URL is returned.
1742 * Failing that, the given location is interpreted as a directory name relative to the project's base directory.
1743 * If that directory is found, the URL of that directory is returned. Otherwise {@code null} is returned.</p>
1744 *
1745 * @param location The directory location to create an {@code URL} from.
1746 *
1747 * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and
1748 * {@code location} points to a non-existent directory.
1749 *
1750 * @throws NullPointerException if {@code location} is {@code null}.
1751 * @throws MojoExecutionException if creating an URL fails.
1752 *
1753 * @since 1.2
1754 */
1755 protected URL getDirectory( final String location ) throws MojoExecutionException
1756 {
1757 if ( location == null )
1758 {
1759 throw new NullPointerException( "location" );
1760 }
1761
1762 try
1763 {
1764 URL resource = null;
1765
1766 try
1767 {
1768 resource = new URL( location );
1769 }
1770 catch ( final MalformedURLException e )
1771 {
1772 if ( this.isLoggable( Level.FINEST ) )
1773 {
1774 this.log( Level.FINEST, Messages.getMessage( e ), e );
1775 }
1776
1777 resource = null;
1778 }
1779
1780 if ( resource == null )
1781 {
1782 final File f = this.getAbsoluteFile( location );
1783
1784 if ( f.isDirectory() )
1785 {
1786 resource = f.toURI().toURL();
1787 }
1788 }
1789
1790 return resource;
1791 }
1792 catch ( final MalformedURLException e )
1793 {
1794 String m = Messages.getMessage( e );
1795 m = m == null ? "" : " " + m;
1796
1797 throw new MojoExecutionException( Messages.getMessage( "malformedLocation", location, m ), e );
1798 }
1799 }
1800
1801 /**
1802 * Creates a new {@code Transformer} from a given {@code TransformerResourceType}.
1803 *
1804 * @param resource The resource to initialize the transformer with.
1805 *
1806 * @return A {@code Transformer} for {@code resource} or {@code null}, if {@code resource} is not found and flagged
1807 * optional.
1808 *
1809 * @throws NullPointerException if {@code resource} is {@code null}.
1810 * @throws MojoExecutionException if creating a transformer fails.
1811 *
1812 * @see #getResource(java.lang.String)
1813 * @since 1.2
1814 */
1815 protected Transformer getTransformer( final TransformerResourceType resource ) throws MojoExecutionException
1816 {
1817 if ( resource == null )
1818 {
1819 throw new NullPointerException( "resource" );
1820 }
1821
1822 InputStream in = null;
1823 boolean suppressExceptionOnClose = true;
1824 final URL url = this.getResource( resource.getLocation() );
1825 final ErrorListener errorListener = new ErrorListener()
1826 {
1827
1828 public void warning( final TransformerException exception ) throws TransformerException
1829 {
1830 try
1831 {
1832 log( Level.WARNING, Messages.getMessage( exception ), exception );
1833 }
1834 catch ( final MojoExecutionException e )
1835 {
1836 getLog().warn( exception );
1837 getLog().error( e );
1838 }
1839 }
1840
1841 public void error( final TransformerException exception ) throws TransformerException
1842 {
1843 try
1844 {
1845 log( Level.SEVERE, Messages.getMessage( exception ), exception );
1846 }
1847 catch ( final MojoExecutionException e )
1848 {
1849 getLog().error( exception );
1850 getLog().error( e );
1851 }
1852
1853 throw exception;
1854 }
1855
1856 public void fatalError( final TransformerException exception ) throws TransformerException
1857 {
1858 try
1859 {
1860 log( Level.SEVERE, Messages.getMessage( exception ), exception );
1861 }
1862 catch ( final MojoExecutionException e )
1863 {
1864 getLog().error( exception );
1865 getLog().error( e );
1866 }
1867
1868 throw exception;
1869 }
1870
1871 };
1872
1873 try
1874 {
1875 if ( url != null )
1876 {
1877 if ( this.isLoggable( Level.FINER ) )
1878 {
1879 this.log( Level.FINER, Messages.getMessage( "loadingTransformer", url.toExternalForm() ), null );
1880 }
1881
1882 final URLConnection con = url.openConnection();
1883 con.setConnectTimeout( resource.getConnectTimeout() );
1884 con.setReadTimeout( resource.getReadTimeout() );
1885 con.connect();
1886 in = con.getInputStream();
1887
1888 final TransformerFactory transformerFactory = TransformerFactory.newInstance();
1889 transformerFactory.setErrorListener( errorListener );
1890 final Transformer transformer =
1891 transformerFactory.newTransformer( new StreamSource( in, url.toURI().toASCIIString() ) );
1892
1893 transformer.setErrorListener( errorListener );
1894
1895 for ( final Map.Entry<Object, Object> e : System.getProperties().entrySet() )
1896 {
1897 transformer.setParameter( e.getKey().toString(), e.getValue() );
1898 }
1899
1900 if ( this.getMavenProject().getProperties() != null )
1901 {
1902 for ( final Map.Entry<Object, Object> e : this.getMavenProject().getProperties().entrySet() )
1903 {
1904 transformer.setParameter( e.getKey().toString(), e.getValue() );
1905 }
1906 }
1907
1908 if ( this.transformationParameterResources != null )
1909 {
1910 for ( int i = 0, s0 = this.transformationParameterResources.size(); i < s0; i++ )
1911 {
1912 for ( final Map.Entry<Object, Object> e : this.getProperties(
1913 this.transformationParameterResources.get( i ) ).entrySet() )
1914 {
1915 transformer.setParameter( e.getKey().toString(), e.getValue() );
1916 }
1917 }
1918 }
1919
1920 if ( this.transformationParameters != null )
1921 {
1922 for ( final TransformationParameter e : this.transformationParameters )
1923 {
1924 transformer.setParameter( e.getKey(), e.getObject() );
1925 }
1926 }
1927
1928 if ( this.transformationOutputProperties != null )
1929 {
1930 for ( final TransformationOutputProperty e : this.transformationOutputProperties )
1931 {
1932 transformer.setOutputProperty( e.getKey(), e.getValue() );
1933 }
1934 }
1935
1936 for ( int i = 0, s0 = resource.getTransformationParameterResources().size(); i < s0; i++ )
1937 {
1938 for ( final Map.Entry<Object, Object> e : this.getProperties(
1939 resource.getTransformationParameterResources().get( i ) ).entrySet() )
1940 {
1941 transformer.setParameter( e.getKey().toString(), e.getValue() );
1942 }
1943 }
1944
1945 for ( final TransformationParameter e : resource.getTransformationParameters() )
1946 {
1947 transformer.setParameter( e.getKey(), e.getObject() );
1948 }
1949
1950 for ( final TransformationOutputProperty e : resource.getTransformationOutputProperties() )
1951 {
1952 transformer.setOutputProperty( e.getKey(), e.getValue() );
1953 }
1954
1955 suppressExceptionOnClose = false;
1956 return transformer;
1957 }
1958 else if ( resource.isOptional() )
1959 {
1960 if ( this.isLoggable( Level.WARNING ) )
1961 {
1962 this.log( Level.WARNING, Messages.getMessage(
1963 "transformerNotFound", resource.getLocation() ), null );
1964
1965 }
1966 }
1967 else
1968 {
1969 throw new MojoExecutionException( Messages.getMessage(
1970 "transformerNotFound", resource.getLocation() ) );
1971
1972 }
1973 }
1974 catch ( final InstantiationException e )
1975 {
1976 throw new MojoExecutionException( Messages.getMessage( e ), e );
1977 }
1978 catch ( final URISyntaxException e )
1979 {
1980 throw new MojoExecutionException( Messages.getMessage( e ), e );
1981 }
1982 catch ( final TransformerConfigurationException e )
1983 {
1984 String m = Messages.getMessage( e );
1985 if ( m == null )
1986 {
1987 m = Messages.getMessage( e.getException() );
1988 }
1989
1990 m = m == null ? "" : " " + m;
1991
1992 throw new MojoExecutionException( Messages.getMessage(
1993 "failedCreatingTransformer", resource.getLocation(), m ), e );
1994
1995 }
1996 catch ( final SocketTimeoutException e )
1997 {
1998 String m = Messages.getMessage( e );
1999 m = m == null ? "" : " " + m;
2000
2001 if ( resource.isOptional() )
2002 {
2003 if ( this.isLoggable( Level.WARNING ) )
2004 {
2005 this.log( Level.WARNING, Messages.getMessage(
2006 "failedLoadingTransformer", url.toExternalForm(), m ), e );
2007
2008 }
2009 }
2010 else
2011 {
2012 throw new MojoExecutionException( Messages.getMessage(
2013 "failedLoadingTransformer", url.toExternalForm(), m ), e );
2014
2015 }
2016 }
2017 catch ( final IOException e )
2018 {
2019 String m = Messages.getMessage( e );
2020 m = m == null ? "" : " " + m;
2021
2022 if ( resource.isOptional() )
2023 {
2024 if ( this.isLoggable( Level.WARNING ) )
2025 {
2026 this.log( Level.WARNING, Messages.getMessage(
2027 "failedLoadingTransformer", url.toExternalForm(), m ), e );
2028
2029 }
2030 }
2031 else
2032 {
2033 throw new MojoExecutionException( Messages.getMessage(
2034 "failedLoadingTransformer", url.toExternalForm(), m ), e );
2035
2036 }
2037 }
2038 finally
2039 {
2040 try
2041 {
2042 if ( in != null )
2043 {
2044 in.close();
2045 }
2046 }
2047 catch ( final IOException e )
2048 {
2049 if ( suppressExceptionOnClose )
2050 {
2051 this.getLog().error( e );
2052 }
2053 else
2054 {
2055 throw new MojoExecutionException( Messages.getMessage( e ), e );
2056 }
2057 }
2058 }
2059
2060 return null;
2061 }
2062
2063 /**
2064 * Creates a new {@code Properties} instance from a {@code PropertiesResourceType}.
2065 *
2066 * @param propertiesResourceType The {@code PropertiesResourceType} specifying the properties to create.
2067 *
2068 * @return The properties for {@code propertiesResourceType}.
2069 *
2070 * @throws NullPointerException if {@code propertiesResourceType} is {@code null}.
2071 * @throws MojoExecutionException if loading properties fails.
2072 *
2073 * @see #getResource(java.lang.String)
2074 * @since 1.2
2075 */
2076 protected Properties getProperties( final PropertiesResourceType propertiesResourceType )
2077 throws MojoExecutionException
2078 {
2079 if ( propertiesResourceType == null )
2080 {
2081 throw new NullPointerException( "propertiesResourceType" );
2082 }
2083
2084 InputStream in = null;
2085 boolean suppressExceptionOnClose = true;
2086 final URL url = this.getResource( propertiesResourceType.getLocation() );
2087 final Properties properties = new Properties();
2088
2089 try
2090 {
2091 if ( url != null )
2092 {
2093 if ( this.isLoggable( Level.FINER ) )
2094 {
2095 this.log( Level.FINER, Messages.getMessage( "loadingProperties", url.toExternalForm() ), null );
2096 }
2097
2098 final URLConnection con = url.openConnection();
2099 con.setConnectTimeout( propertiesResourceType.getConnectTimeout() );
2100 con.setReadTimeout( propertiesResourceType.getReadTimeout() );
2101 con.connect();
2102
2103 in = con.getInputStream();
2104
2105 if ( PropertiesResourceType.PLAIN_FORMAT.equalsIgnoreCase( propertiesResourceType.getFormat() ) )
2106 {
2107 properties.load( in );
2108 }
2109 else if ( PropertiesResourceType.XML_FORMAT.equalsIgnoreCase( propertiesResourceType.getFormat() ) )
2110 {
2111 properties.loadFromXML( in );
2112 }
2113 }
2114 else if ( propertiesResourceType.isOptional() )
2115 {
2116 if ( this.isLoggable( Level.WARNING ) )
2117 {
2118 this.log( Level.WARNING, Messages.getMessage(
2119 "propertiesNotFound", propertiesResourceType.getLocation() ), null );
2120
2121 }
2122 }
2123 else
2124 {
2125 throw new MojoExecutionException( Messages.getMessage(
2126 "propertiesNotFound", propertiesResourceType.getLocation() ) );
2127
2128 }
2129
2130 suppressExceptionOnClose = false;
2131 }
2132 catch ( final SocketTimeoutException e )
2133 {
2134 String m = Messages.getMessage( e );
2135 m = m == null ? "" : " " + m;
2136
2137 if ( propertiesResourceType.isOptional() )
2138 {
2139 if ( this.isLoggable( Level.WARNING ) )
2140 {
2141 this.log( Level.WARNING, Messages.getMessage(
2142 "failedLoadingProperties", url.toExternalForm(), m ), e );
2143
2144 }
2145 }
2146 else
2147 {
2148 throw new MojoExecutionException( Messages.getMessage(
2149 "failedLoadingProperties", url.toExternalForm(), m ), e );
2150
2151 }
2152 }
2153 catch ( final IOException e )
2154 {
2155 String m = Messages.getMessage( e );
2156 m = m == null ? "" : " " + m;
2157
2158 if ( propertiesResourceType.isOptional() )
2159 {
2160 if ( this.isLoggable( Level.WARNING ) )
2161 {
2162 this.log( Level.WARNING, Messages.getMessage(
2163 "failedLoadingProperties", url.toExternalForm(), m ), e );
2164
2165 }
2166 }
2167 else
2168 {
2169 throw new MojoExecutionException( Messages.getMessage(
2170 "failedLoadingProperties", url.toExternalForm(), m ), e );
2171
2172 }
2173 }
2174 finally
2175 {
2176 try
2177 {
2178 if ( in != null )
2179 {
2180 in.close();
2181 }
2182 }
2183 catch ( final IOException e )
2184 {
2185 if ( suppressExceptionOnClose )
2186 {
2187 this.getLog().error( e );
2188 }
2189 else
2190 {
2191 throw new MojoExecutionException( Messages.getMessage( e ), e );
2192 }
2193 }
2194 }
2195
2196 return properties;
2197 }
2198
2199 /**
2200 * Tests if messages at a given level are logged.
2201 *
2202 * @param level The level to test.
2203 *
2204 * @return {@code true}, if messages at {@code level} are logged; {@code false}, if messages at {@code level} are
2205 * suppressed.
2206 *
2207 * @throws NullPointerException if {@code level} is {@code null}.
2208 * @throws MojoExecutionException if testing the level fails.
2209 *
2210 * @see #isVerbose()
2211 * @since 1.2
2212 */
2213 protected boolean isLoggable( final Level level ) throws MojoExecutionException
2214 {
2215 if ( level == null )
2216 {
2217 throw new NullPointerException( "level" );
2218 }
2219
2220 boolean loggable = false;
2221
2222 if ( level.intValue() <= Level.CONFIG.intValue() )
2223 {
2224 loggable = this.getLog().isDebugEnabled();
2225 }
2226 else if ( level.intValue() <= Level.INFO.intValue() )
2227 {
2228 loggable = this.getLog().isInfoEnabled() && this.isVerbose();
2229 }
2230 else if ( level.intValue() <= Level.WARNING.intValue() )
2231 {
2232 loggable = this.getLog().isWarnEnabled();
2233 }
2234 else if ( level.intValue() <= Level.SEVERE.intValue() )
2235 {
2236 loggable = this.getLog().isErrorEnabled();
2237 }
2238
2239 return loggable;
2240 }
2241
2242 /**
2243 * Logs a separator at a given level.
2244 *
2245 * @param level The level to log a separator at.
2246 *
2247 * @throws MojoExecutionException if logging fails.
2248 *
2249 * @deprecated As of JOMC 1.1, please use method {@link #logSeparator()}. This method will be removed in version
2250 * 2.0.
2251 */
2252 @Deprecated
2253 protected void logSeparator( final Level level ) throws MojoExecutionException
2254 {
2255 this.logSeparator();
2256 }
2257
2258 /**
2259 * Logs a separator.
2260 *
2261 * @throws MojoExecutionException if logging fails.
2262 *
2263 * @since 1.1
2264 */
2265 protected void logSeparator() throws MojoExecutionException
2266 {
2267 if ( this.isLoggable( Level.INFO ) )
2268 {
2269 this.log( Level.INFO, Messages.getMessage( "separator" ), null );
2270 }
2271 }
2272
2273 /**
2274 * Logs a message stating a tool is starting to process a module.
2275 *
2276 * @param toolName The tool starting execution.
2277 * @param module The module getting processed.
2278 *
2279 * @throws MojoExecutionException if logging fails.
2280 */
2281 protected void logProcessingModule( final String toolName, final String module ) throws MojoExecutionException
2282 {
2283 if ( this.isLoggable( Level.INFO ) )
2284 {
2285 this.log( Level.INFO, Messages.getMessage( "processingModule", toolName, module ), null );
2286 }
2287 }
2288
2289 /**
2290 * Logs a message stating a tool is starting to process a model.
2291 *
2292 * @param toolName The tool starting execution.
2293 * @param model The model getting processed.
2294 *
2295 * @throws MojoExecutionException if logging fails.
2296 *
2297 * @since 1.1
2298 */
2299 protected void logProcessingModel( final String toolName, final String model ) throws MojoExecutionException
2300 {
2301 if ( this.isLoggable( Level.INFO ) )
2302 {
2303 this.log( Level.INFO, Messages.getMessage( "processingModel", toolName, model ), null );
2304 }
2305 }
2306
2307 /**
2308 * Logs a message stating that a module has not been found.
2309 *
2310 * @param module The module not having been found.
2311 *
2312 * @throws MojoExecutionException if logging fails.
2313 */
2314 protected void logMissingModule( final String module ) throws MojoExecutionException
2315 {
2316 if ( this.isLoggable( Level.WARNING ) )
2317 {
2318 this.log( Level.WARNING, Messages.getMessage( "missingModule", module ), null );
2319 }
2320 }
2321
2322 /**
2323 * Logs a message stating that a tool successfully completed execution.
2324 *
2325 * @param toolName The name of the tool.
2326 *
2327 * @throws MojoExecutionException if logging fails.
2328 */
2329 protected void logToolSuccess( final String toolName ) throws MojoExecutionException
2330 {
2331 if ( this.isLoggable( Level.INFO ) )
2332 {
2333 this.log( Level.INFO, Messages.getMessage( "toolSuccess", toolName ), null );
2334 }
2335 }
2336
2337 /**
2338 * Logs a {@code ModelValidationReport}.
2339 *
2340 * @param context The context to use when marshalling detail elements of the report.
2341 * @param level The level to log at.
2342 * @param report The report to log.
2343 *
2344 * @throws MojoExecutionException if logging {@code report} fails.
2345 */
2346 protected void log( final ModelContext context, final Level level, final ModelValidationReport report )
2347 throws MojoExecutionException
2348 {
2349 try
2350 {
2351 if ( !report.getDetails().isEmpty() )
2352 {
2353 this.logSeparator();
2354 Marshaller marshaller = null;
2355
2356 for ( final ModelValidationReport.Detail detail : report.getDetails() )
2357 {
2358 this.log( detail.getLevel(), "o " + detail.getMessage(), null );
2359
2360 if ( detail.getElement() != null && this.isLoggable( Level.FINEST ) )
2361 {
2362 if ( marshaller == null )
2363 {
2364 marshaller = context.createMarshaller( this.getModel() );
2365 marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
2366 }
2367
2368 final StringWriter stringWriter = new StringWriter();
2369 marshaller.marshal( detail.getElement(), stringWriter );
2370 this.log( Level.FINEST, stringWriter.toString(), null );
2371 }
2372 }
2373 }
2374 }
2375 catch ( final ModelException e )
2376 {
2377 throw new MojoExecutionException( Messages.getMessage( e ), e );
2378 }
2379 catch ( final JAXBException e )
2380 {
2381 String message = Messages.getMessage( e );
2382 if ( message == null && e.getLinkedException() != null )
2383 {
2384 message = Messages.getMessage( e.getLinkedException() );
2385 }
2386
2387 throw new MojoExecutionException( message, e );
2388 }
2389 }
2390
2391 /**
2392 * Logs a message and throwable at a given level.
2393 *
2394 * @param level The level to log at.
2395 * @param message The message to log or {@code null}.
2396 * @param throwable The throwable to log or {@code null}.
2397 *
2398 * @throws MojoExecutionException if logging fails.
2399 */
2400 protected void log( final Level level, final String message, final Throwable throwable )
2401 throws MojoExecutionException
2402 {
2403 BufferedReader reader = null;
2404 boolean suppressExceptionOnClose = true;
2405
2406 try
2407 {
2408 if ( this.isLoggable( level ) )
2409 {
2410 String line;
2411 reader = new BufferedReader( new StringReader( message == null ? "" : message ) );
2412 boolean throwableLogged = false;
2413
2414 while ( ( line = reader.readLine() ) != null )
2415 {
2416 final String mojoMessage =
2417 Messages.getMessage( this.getLog().isDebugEnabled() ? "debugMessage" : "logMessage", line,
2418 Thread.currentThread().getName(), new Date( System.currentTimeMillis() ) );
2419
2420 if ( level.intValue() <= Level.CONFIG.intValue() )
2421 {
2422 this.getLog().debug( mojoMessage, throwableLogged ? null : throwable );
2423 }
2424 else if ( level.intValue() <= Level.INFO.intValue() )
2425 {
2426 this.getLog().info( mojoMessage, throwableLogged ? null : throwable );
2427 }
2428 else if ( level.intValue() <= Level.WARNING.intValue() )
2429 {
2430 this.getLog().warn( mojoMessage, throwableLogged ? null : throwable );
2431 }
2432 else if ( level.intValue() <= Level.SEVERE.intValue() )
2433 {
2434 this.getLog().error( mojoMessage, throwableLogged ? null : throwable );
2435 }
2436
2437 throwableLogged = true;
2438 }
2439 }
2440
2441 suppressExceptionOnClose = false;
2442 }
2443 catch ( final IOException e )
2444 {
2445 this.getLog().error( e );
2446 throw new AssertionError( e );
2447 }
2448 finally
2449 {
2450 try
2451 {
2452 if ( reader != null )
2453 {
2454 reader.close();
2455 }
2456 }
2457 catch ( final IOException e )
2458 {
2459 if ( !suppressExceptionOnClose )
2460 {
2461 throw new AssertionError( e );
2462 }
2463 }
2464 }
2465 }
2466
2467 /**
2468 * Configures a {@code ModelContext} instance.
2469 *
2470 * @param context The model context to configure.
2471 *
2472 * @throws NullPointerException if {@code context} is {@code null}.
2473 * @throws MojoExecutionException if configuring {@code context} fails.
2474 */
2475 protected void setupModelContext( final ModelContext context ) throws MojoExecutionException
2476 {
2477 if ( context == null )
2478 {
2479 throw new NullPointerException( "context" );
2480 }
2481
2482 if ( this.isVerbose() || this.getLog().isDebugEnabled() )
2483 {
2484 context.setLogLevel( this.getLog().isDebugEnabled() ? Level.ALL : Level.INFO );
2485 }
2486
2487 try
2488 {
2489 context.setModletSchemaSystemId( this.modletSchemaSystemId );
2490 context.getListeners().add( new ModelContext.Listener()
2491 {
2492
2493 @Override
2494 public void onLog( final Level level, final String message, final Throwable t )
2495 {
2496 super.onLog( level, message, t );
2497
2498 try
2499 {
2500 log( level, message, t );
2501 }
2502 catch ( final MojoExecutionException e )
2503 {
2504 getLog().error( e );
2505 }
2506 }
2507
2508 } );
2509
2510 if ( this.providerLocation != null )
2511 {
2512 context.setAttribute( DefaultModelContext.PROVIDER_LOCATION_ATTRIBUTE_NAME, this.providerLocation );
2513 }
2514
2515 if ( this.platformProviderLocation != null )
2516 {
2517 context.setAttribute( DefaultModelContext.PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME,
2518 this.platformProviderLocation );
2519
2520 }
2521
2522 if ( this.modletLocation != null )
2523 {
2524 context.setAttribute( DefaultModletProvider.MODLET_LOCATION_ATTRIBUTE_NAME, this.modletLocation );
2525 }
2526
2527 if ( this.transformerLocation != null )
2528 {
2529 context.setAttribute( DefaultModelProcessor.TRANSFORMER_LOCATION_ATTRIBUTE_NAME,
2530 this.transformerLocation );
2531 }
2532
2533 if ( this.moduleLocation != null )
2534 {
2535 context.setAttribute( DefaultModelProvider.MODULE_LOCATION_ATTRIBUTE_NAME, this.moduleLocation );
2536 }
2537
2538 context.setAttribute( ToolsModelProvider.MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME,
2539 this.modelObjectClasspathResolutionEnabled );
2540
2541 context.setAttribute( ToolsModelProcessor.MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME,
2542 this.modelObjectClasspathResolutionEnabled );
2543
2544 context.setAttribute( DefaultModletProvider.VALIDATING_ATTRIBUTE_NAME,
2545 this.modletResourceValidationEnabled );
2546
2547 context.setAttribute( DefaultModelProvider.VALIDATING_ATTRIBUTE_NAME, this.modelResourceValidationEnabled );
2548 context.setAttribute( DefaultModelValidator.VALIDATE_JAVA_ATTRIBUTE_NAME, this.javaValidationEnabled );
2549
2550 if ( this.modelContextAttributes != null )
2551 {
2552 for ( final ModelContextAttribute e : this.modelContextAttributes )
2553 {
2554 final Object object = e.getObject();
2555
2556 if ( object != null )
2557 {
2558 context.setAttribute( e.getKey(), object );
2559 }
2560 else
2561 {
2562 context.clearAttribute( e.getKey() );
2563 }
2564 }
2565 }
2566
2567 if ( ( this.modletIncludes != null && !this.modletIncludes.isEmpty() )
2568 || ( this.modletExcludes != null && !this.modletExcludes.isEmpty() ) )
2569 {
2570 final Modlets modlets = context.getModlets().clone();
2571
2572 for ( final Iterator<Modlet> it = modlets.getModlet().iterator(); it.hasNext(); )
2573 {
2574 final Modlet modlet = it.next();
2575
2576 if ( this.modletIncludes != null
2577 && !this.modletIncludes.isEmpty()
2578 && !this.modletIncludes.contains( modlet.getName() ) )
2579 {
2580 it.remove();
2581 this.log( Level.INFO, Messages.getMessage( "excludingModlet", modlet.getName() ), null );
2582 continue;
2583 }
2584
2585 if ( this.modletExcludes != null
2586 && !this.modletExcludes.isEmpty()
2587 && this.modletExcludes.contains( modlet.getName() ) )
2588 {
2589 it.remove();
2590 this.log( Level.INFO, Messages.getMessage( "excludingModlet", modlet.getName() ), null );
2591 continue;
2592 }
2593
2594 this.log( Level.INFO, Messages.getMessage( "includingModlet", modlet.getName() ), null );
2595 }
2596
2597 context.setModlets( modlets );
2598 }
2599 }
2600 catch ( final InstantiationException e )
2601 {
2602 throw new MojoExecutionException( Messages.getMessage( e ), e );
2603 }
2604 catch ( final ModelException e )
2605 {
2606 throw new MojoExecutionException( Messages.getMessage( e ), e );
2607 }
2608 }
2609
2610 /**
2611 * Configures a {@code JomcTool} instance.
2612 *
2613 * @param context The model context to use for configuring {@code tool}.
2614 * @param tool The tool to configure.
2615 *
2616 * @throws NullPointerException if {@code context} of {@code tool} is {@code null}.
2617 * @throws MojoExecutionException if configuring {@code tool} fails.
2618 */
2619 protected void setupJomcTool( final ModelContext context, final JomcTool tool ) throws MojoExecutionException
2620 {
2621 if ( context == null )
2622 {
2623 throw new NullPointerException( "context" );
2624 }
2625 if ( tool == null )
2626 {
2627 throw new NullPointerException( "tool" );
2628 }
2629
2630 try
2631 {
2632 if ( this.isVerbose() || this.getLog().isDebugEnabled() )
2633 {
2634 tool.setLogLevel( this.getLog().isDebugEnabled() ? Level.ALL : Level.INFO );
2635 }
2636
2637 tool.getListeners().add( new JomcTool.Listener()
2638 {
2639
2640 @Override
2641 public void onLog( final Level level, final String message, final Throwable t )
2642 {
2643 super.onLog( level, message, t );
2644
2645 try
2646 {
2647 log( level, message, t );
2648 }
2649 catch ( final MojoExecutionException e )
2650 {
2651 getLog().error( e );
2652 }
2653 }
2654
2655 } );
2656
2657 if ( this.templateEncoding != null )
2658 {
2659 if ( this.isLoggable( Level.WARNING ) )
2660 {
2661 this.log( Level.WARNING, Messages.getMessage(
2662 "deprecationWarning", "templateEncoding", "defaultTemplateEncoding" ), null );
2663
2664 }
2665
2666 tool.setDefaultTemplateEncoding( this.templateEncoding );
2667 }
2668 else
2669 {
2670 tool.setDefaultTemplateEncoding( this.defaultTemplateEncoding );
2671 }
2672
2673 tool.setInputEncoding( this.sourceEncoding );
2674 tool.setOutputEncoding( this.sourceEncoding );
2675 tool.setDefaultTemplateProfile( this.defaultTemplateProfile );
2676 tool.setTemplateProfile( this.templateProfile );
2677 tool.setModel( this.getModel( context ) );
2678
2679 if ( this.indentation != null )
2680 {
2681 tool.setIndentation( StringEscapeUtils.unescapeJava( this.indentation ) );
2682 }
2683
2684 if ( this.lineSeparator != null )
2685 {
2686 tool.setLineSeparator( StringEscapeUtils.unescapeJava( this.lineSeparator ) );
2687 }
2688
2689 if ( this.locale != null )
2690 {
2691 tool.setLocale( new Locale( StringUtils.defaultString( this.locale.getLanguage() ),
2692 StringUtils.defaultString( this.locale.getCountry() ),
2693 StringUtils.defaultString( this.locale.getVariant() ) ) );
2694
2695 }
2696
2697 if ( this.velocityPropertyResources != null )
2698 {
2699 for ( int i = 0, s0 = this.velocityPropertyResources.size(); i < s0; i++ )
2700 {
2701 for ( final Map.Entry<Object, Object> e : this.getProperties(
2702 this.velocityPropertyResources.get( i ) ).entrySet() )
2703 {
2704 if ( e.getValue() != null )
2705 {
2706 tool.getVelocityEngine().setProperty( e.getKey().toString(), e );
2707 }
2708 else
2709 {
2710 tool.getVelocityEngine().clearProperty( e.getKey().toString() );
2711 }
2712 }
2713 }
2714 }
2715
2716 if ( this.velocityProperties != null )
2717 {
2718 for ( final VelocityProperty e : this.velocityProperties )
2719 {
2720 final Object object = e.getObject();
2721
2722 if ( object != null )
2723 {
2724 tool.getVelocityEngine().setProperty( e.getKey(), object );
2725 }
2726 else
2727 {
2728 tool.getVelocityEngine().clearProperty( e.getKey() );
2729 }
2730 }
2731 }
2732
2733 for ( final Map.Entry<Object, Object> e : System.getProperties().entrySet() )
2734 {
2735 tool.getTemplateParameters().put( e.getKey().toString(), e.getValue() );
2736 }
2737
2738 if ( this.getMavenProject().getProperties() != null )
2739 {
2740 for ( final Map.Entry<Object, Object> e : System.getProperties().entrySet() )
2741 {
2742 tool.getTemplateParameters().put( e.getKey().toString(), e.getValue() );
2743 }
2744 }
2745
2746 if ( this.templateParameterResources != null )
2747 {
2748 for ( int i = 0, s0 = this.templateParameterResources.size(); i < s0; i++ )
2749 {
2750 for ( final Map.Entry<Object, Object> e : this.getProperties(
2751 this.templateParameterResources.get( i ) ).entrySet() )
2752 {
2753 if ( e.getValue() != null )
2754 {
2755 tool.getTemplateParameters().put( e.getKey().toString(), e.getValue() );
2756 }
2757 else
2758 {
2759 tool.getTemplateParameters().remove( e.getKey().toString() );
2760 }
2761 }
2762 }
2763 }
2764
2765 if ( this.templateParameters != null )
2766 {
2767 for ( final TemplateParameter e : this.templateParameters )
2768 {
2769 final Object object = e.getObject();
2770
2771 if ( object != null )
2772 {
2773 tool.getTemplateParameters().put( e.getKey(), object );
2774 }
2775 else
2776 {
2777 tool.getTemplateParameters().remove( e.getKey() );
2778 }
2779 }
2780 }
2781
2782 if ( this.templateLocation != null )
2783 {
2784 final URL url = this.getDirectory( this.templateLocation );
2785 tool.setTemplateLocation( url );
2786
2787 if ( url == null && this.isLoggable( Level.WARNING ) )
2788 {
2789 this.log( Level.WARNING, Messages.getMessage( "locationNotFound", this.templateLocation ), null );
2790 }
2791 }
2792 }
2793 catch ( final InstantiationException e )
2794 {
2795 throw new MojoExecutionException( Messages.getMessage( e ), e );
2796 }
2797 catch ( final IOException e )
2798 {
2799 throw new MojoExecutionException( Messages.getMessage( e ), e );
2800 }
2801 }
2802
2803 private Artifact getPluginArtifact( final Artifact a )
2804 {
2805 for ( int i = 0, s0 = this.pluginArtifacts.size(); i < s0; i++ )
2806 {
2807 final Artifact pluginArtifact = this.pluginArtifacts.get( i );
2808
2809 if ( pluginArtifact.getGroupId().equals( a.getGroupId() )
2810 && pluginArtifact.getArtifactId().equals( a.getArtifactId() )
2811 && ( pluginArtifact.hasClassifier()
2812 ? pluginArtifact.getClassifier().equals( a.getClassifier() )
2813 : !a.hasClassifier() ) )
2814 {
2815 return pluginArtifact;
2816 }
2817 }
2818
2819 return null;
2820 }
2821
2822 }