View Javadoc

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      * &lt;locale>
233      *   &lt;language>Lowercase two-letter ISO-639 code.&lt;/language>
234      *   &lt;country>Uppercase two-letter ISO-3166 code.&lt;/country>
235      *   &lt;variant>Vendor and browser specific code.&lt;/variant>
236      * &lt;/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      * &lt;velocityProperties>
373      *   &lt;velocityProperty>
374      *     &lt;key>The name of the property.&lt;/key>
375      *     &lt;value>The value of the property.&lt;/value>
376      *     &lt;type>The name of the class of the properties object.&lt;/type>
377      *   &lt;/velocityProperty>
378      * &lt;/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      * &lt;velocityPropertyResources>
390      *   &lt;velocityPropertyResource>
391      *     &lt;location>The location of the properties resource.&lt;/location>
392      *     &lt;optional>Flag indicating the properties resource is optional.&lt;/optional>
393      *     &lt;format>The format of the properties resource.&lt;/format>
394      *     &lt;connectTimeout>Timeout value, in milliseconds.&lt;/connectTimeout>
395      *     &lt;readTimeout>Timeout value, in milliseconds.&lt;/readTimeout>
396      *   &lt;/velocityPropertyResource>
397      * &lt;/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      * &lt;templateParameters>
424      *   &lt;templateParameter>
425      *     &lt;key>The name of the parameter.&lt;/key>
426      *     &lt;value>The value of the parameter.&lt;/value>
427      *     &lt;type>The name of the class of the parameter's object.&lt;/type>
428      *   &lt;/templateParameter>
429      * &lt;/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      * &lt;templateParameterResources>
441      *   &lt;templateParameterResource>
442      *     &lt;location>The location of the properties resource.&lt;/location>
443      *     &lt;optional>Flag indicating the properties resource is optional.&lt;/optional>
444      *     &lt;format>The format of the properties resource.&lt;/format>
445      *     &lt;connectTimeout>Timeout value, in milliseconds.&lt;/connectTimeout>
446      *     &lt;readTimeout>Timeout value, in milliseconds.&lt;/readTimeout>
447      *   &lt;/templateParameterResource>
448      * &lt;/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      * &lt;transformationParameters>
475      *   &lt;transformationParameter>
476      *     &lt;key>The name of the parameter.&lt;/key>
477      *     &lt;value>The value of the parameter.&lt;/value>
478      *     &lt;type>The name of the class of the parameter's object.&lt;/type>
479      *   &lt;/transformationParameter>
480      * &lt;/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      * &lt;transformationOutputProperties>
492      *   &lt;transformationOutputProperty>
493      *     &lt;key>The name of the property.&lt;/key>
494      *     &lt;value>The value of the property.&lt;/value>
495      *     &lt;type>The name of the class of the properties object.&lt;/type>
496      *   &lt;/transformationOutputProperty>
497      * &lt;/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      * &lt;transformationParameterResources>
509      *   &lt;transformationParameterResource>
510      *     &lt;location>The location of the properties resource.&lt;/location>
511      *     &lt;optional>Flag indicating the properties resource is optional.&lt;/optional>
512      *     &lt;format>The format of the properties resource.&lt;/format>
513      *     &lt;connectTimeout>Timeout value, in milliseconds.&lt;/connectTimeout>
514      *     &lt;readTimeout>Timeout value, in milliseconds.&lt;/readTimeout>
515      *   &lt;/transformationParameterResource>
516      * &lt;/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      * &lt;modelContextAttributes>
568      *   &lt;modelContextAttribute>
569      *     &lt;key>The name of the attribute.&lt;/key>
570      *     &lt;value>The value of the attribute.&lt;/value>
571      *     &lt;type>The name of the class of the attributes's object.&lt;/type>
572      *   &lt;/modelContextAttribute>
573      * &lt;/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 }