View Javadoc
1   /*
2    *   Copyright (C) Christian Schulte <cs@schulte.it>, 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 5043 2015-05-27 07:03:39Z 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 5043 2015-05-27 07:03:39Z 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>
115      * <strong>Deprecated:</strong> As of JOMC 1.3, please use the 'defaultTemplateEncoding' parameter. This
116      * parameter will be removed in version 2.0.
117      * </p>
118      *
119      * @parameter expression="${jomc.templateEncoding}"
120      */
121     @Deprecated
122     private String templateEncoding;
123 
124     /**
125      * The encoding to use for reading templates.
126      *
127      * @parameter expression="${jomc.defaultTemplateEncoding}"
128      *
129      * @since 1.3
130      */
131     private String defaultTemplateEncoding;
132 
133     /**
134      * Location to search for templates in addition to searching the class path of the plugin.
135      * <p>
136      * First an attempt is made to parse the location value to an URL. On successful parsing, that URL is used.
137      * Otherwise the location value is interpreted as a directory name relative to the base directory of the project.
138      * If that directory exists, that directory is used. If nothing is found at the given location, a warning message is
139      * logged.
140      * </p>
141      *
142      * @parameter expression="${jomc.templateLocation}"
143      * @since 1.2
144      */
145     private String templateLocation;
146 
147     /**
148      * The template profile to use when accessing templates.
149      *
150      * @parameter expression="${jomc.templateProfile}"
151      */
152     private String templateProfile;
153 
154     /**
155      * The default template profile to use when accessing templates.
156      *
157      * @parameter expression="${jomc.defaultTemplateProfile}"
158      */
159     private String defaultTemplateProfile;
160 
161     /**
162      * The location to search for providers.
163      *
164      * @parameter expression="${jomc.providerLocation}"
165      */
166     private String providerLocation;
167 
168     /**
169      * The location to search for platform providers.
170      *
171      * @parameter expression="${jomc.platformProviderLocation}"
172      */
173     private String platformProviderLocation;
174 
175     /**
176      * The identifier of the model to process.
177      *
178      * @parameter default-value="http://jomc.org/model" expression="${jomc.model}"
179      */
180     private String model;
181 
182     /**
183      * The name of the {@code ModelContextFactory} implementation class backing the task.
184      *
185      * @parameter expression="${jomc.modelContextFactoryClassName}"
186      * @since 1.2
187      */
188     private String modelContextFactoryClassName;
189 
190     /**
191      * The location to search for modlets.
192      *
193      * @parameter expression="${jomc.modletLocation}"
194      */
195     private String modletLocation;
196 
197     /**
198      * The {@code http://jomc.org/modlet} namespace schema system id.
199      *
200      * @parameter expression="${jomc.modletSchemaSystemId}"
201      * @since 1.2
202      */
203     private String modletSchemaSystemId;
204 
205     /**
206      * The location to search for modules.
207      *
208      * @parameter expression="${jomc.moduleLocation}"
209      */
210     private String moduleLocation;
211 
212     /**
213      * The location to search for transformers.
214      *
215      * @parameter expression="${jomc.transformerLocation}"
216      */
217     private String transformerLocation;
218 
219     /**
220      * The indentation string ('\t' for tab).
221      *
222      * @parameter expression="${jomc.indentation}"
223      */
224     private String indentation;
225 
226     /**
227      * The line separator ('\r\n' for DOS, '\r' for Mac, '\n' for Unix).
228      *
229      * @parameter expression="${jomc.lineSeparator}"
230      */
231     private String lineSeparator;
232 
233     /**
234      * The locale.
235      * <pre>
236      * &lt;locale>
237      *   &lt;language>Lowercase two-letter ISO-639 code.&lt;/language>
238      *   &lt;country>Uppercase two-letter ISO-3166 code.&lt;/country>
239      *   &lt;variant>Vendor and browser specific code.&lt;/variant>
240      * &lt;/locale>
241      * </pre>
242      *
243      * @parameter
244      * @since 1.2
245      * @see Locale
246      */
247     private LocaleType locale;
248 
249     /**
250      * Controls verbosity of the plugin.
251      *
252      * @parameter expression="${jomc.verbose}" default-value="false"
253      */
254     private boolean verbose;
255 
256     /**
257      * Controls processing of source code files.
258      *
259      * @parameter expression="${jomc.sourceProcessing}" default-value="true"
260      */
261     private boolean sourceProcessingEnabled;
262 
263     /**
264      * Controls processing of resource files.
265      *
266      * @parameter expression="${jomc.resourceProcessing}" default-value="true"
267      */
268     private boolean resourceProcessingEnabled;
269 
270     /**
271      * Controls processing of class files.
272      *
273      * @parameter expression="${jomc.classProcessing}" default-value="true"
274      */
275     private boolean classProcessingEnabled;
276 
277     /**
278      * Controls processing of models.
279      *
280      * @parameter expression="${jomc.modelProcessing}" default-value="true"
281      */
282     private boolean modelProcessingEnabled;
283 
284     /**
285      * Controls model object class path resolution.
286      *
287      * @parameter expression="${jomc.modelObjectClasspathResolution}" default-value="true"
288      */
289     private boolean modelObjectClasspathResolutionEnabled;
290 
291     /**
292      * Name of the module to process.
293      *
294      * @parameter default-value="${project.name}" expression="${jomc.moduleName}"
295      */
296     private String moduleName;
297 
298     /**
299      * Name of the test module to process.
300      *
301      * @parameter default-value="${project.name} Tests" expression="${jomc.testModuleName}"
302      */
303     private String testModuleName;
304 
305     /**
306      * Directory holding the compiled class files of the project.
307      * <p>
308      * <strong>Deprecated:</strong> As of JOMC 1.1, please use the 'outputDirectory' parameter. This parameter will
309      * be removed in version 2.0.
310      * </p>
311      *
312      * @parameter
313      */
314     @Deprecated
315     private String classesDirectory;
316 
317     /**
318      * Directory holding the compiled test class files of the project.
319      * <p>
320      * <strong>Deprecated:</strong> As of JOMC 1.1, please use the 'testOutputDirectory' parameter. This parameter
321      * will be removed in version 2.0.
322      * </p>
323      *
324      * @parameter
325      */
326     @Deprecated
327     private String testClassesDirectory;
328 
329     /**
330      * Output directory of the project.
331      *
332      * @parameter default-value="${project.build.outputDirectory}" expression="${jomc.outputDirectory}"
333      * @since 1.1
334      */
335     private String outputDirectory;
336 
337     /**
338      * Test output directory of the project.
339      *
340      * @parameter default-value="${project.build.testOutputDirectory}" expression="${jomc.testOutputDirectory}"
341      * @since 1.1
342      */
343     private String testOutputDirectory;
344 
345     /**
346      * Directory holding the source files of the project.
347      *
348      * @parameter default-value="${project.build.sourceDirectory}" expression="${jomc.sourceDirectory}"
349      * @since 1.1
350      */
351     private String sourceDirectory;
352 
353     /**
354      * Directory holding the test source files of the project.
355      *
356      * @parameter default-value="${project.build.testSourceDirectory}" expression="${jomc.testSourceDirectory}"
357      * @since 1.1
358      */
359     private String testSourceDirectory;
360 
361     /**
362      * Directory holding the session related files of the project.
363      *
364      * @parameter default-value="${project.build.directory}/jomc-sessions" expression="${jomc.sessionDirectory}"
365      * @since 1.1
366      */
367     private String sessionDirectory;
368 
369     /**
370      * Directory holding the reports of the project.
371      *
372      * @parameter default-value="${project.reporting.outputDirectory}" expression="${jomc.reportOutputDirectory}"
373      * @since 1.1
374      */
375     private String reportOutputDirectory;
376 
377     /**
378      * Velocity runtime properties.
379      * <pre>
380      * &lt;velocityProperties>
381      *   &lt;velocityProperty>
382      *     &lt;key>The name of the property.&lt;/key>
383      *     &lt;value>The value of the property.&lt;/value>
384      *     &lt;type>The name of the class of the properties object.&lt;/type>
385      *   &lt;/velocityProperty>
386      * &lt;/velocityProperties>
387      * </pre>
388      *
389      * @parameter
390      * @since 1.2
391      */
392     private List<VelocityProperty> velocityProperties;
393 
394     /**
395      * Velocity runtime property resources.
396      * <pre>
397      * &lt;velocityPropertyResources>
398      *   &lt;velocityPropertyResource>
399      *     &lt;location>The location of the properties resource.&lt;/location>
400      *     &lt;optional>Flag indicating the properties resource is optional.&lt;/optional>
401      *     &lt;format>The format of the properties resource.&lt;/format>
402      *     &lt;connectTimeout>Timeout value, in milliseconds.&lt;/connectTimeout>
403      *     &lt;readTimeout>Timeout value, in milliseconds.&lt;/readTimeout>
404      *   &lt;/velocityPropertyResource>
405      * &lt;/velocityPropertyResources>
406      * </pre>
407      * <p>
408      * The location value is used to first search the class path of the plugin and the project's main or test class
409      * path. If a class path resource is found, that resource is used. If no class path resource is found, an attempt is
410      * made to parse the location value to an URL. On successful parsing, that URL is used. Otherwise the location value
411      * is interpreted as a file name relative to the base directory of the project. If that file exists, that file is
412      * used. If nothing is found at the given location, depending on the optional flag, a warning message is logged or a
413      * build failure is produced.
414      * </p>
415      * <p>
416      * The optional flag is used to flag the resource optional. When an optional resource is not found, a warning
417      * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false
418      * </p>
419      * <p>
420      * The format value is used to specify the format of the properties resource. Supported values are {@code plain}
421      * and {@code xml}.<br/><b>Default value is:</b> plain
422      * </p>
423      * <p>
424      * The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening
425      * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/>
426      * <b>Default value is:</b> 60000
427      * </p>
428      * <p>
429      * The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource.
430      * A timeout of zero is interpreted as an infinite timeout.<br/>
431      * <b>Default value is:</b> 60000
432      * </p>
433      *
434      * @parameter
435      * @since 1.2
436      */
437     private List<VelocityPropertyResource> velocityPropertyResources;
438 
439     /**
440      * Template parameters.
441      * <pre>
442      * &lt;templateParameters>
443      *   &lt;templateParameter>
444      *     &lt;key>The name of the parameter.&lt;/key>
445      *     &lt;value>The value of the parameter.&lt;/value>
446      *     &lt;type>The name of the class of the parameter's object.&lt;/type>
447      *   &lt;/templateParameter>
448      * &lt;/templateParameters>
449      * </pre>
450      *
451      * @parameter
452      * @since 1.2
453      */
454     private List<TemplateParameter> templateParameters;
455 
456     /**
457      * Template parameter resources.
458      * <pre>
459      * &lt;templateParameterResources>
460      *   &lt;templateParameterResource>
461      *     &lt;location>The location of the properties resource.&lt;/location>
462      *     &lt;optional>Flag indicating the properties resource is optional.&lt;/optional>
463      *     &lt;format>The format of the properties resource.&lt;/format>
464      *     &lt;connectTimeout>Timeout value, in milliseconds.&lt;/connectTimeout>
465      *     &lt;readTimeout>Timeout value, in milliseconds.&lt;/readTimeout>
466      *   &lt;/templateParameterResource>
467      * &lt;/templateParameterResources>
468      * </pre>
469      * <p>
470      * The location value is used to first search the class path of the plugin and the project's main or test class
471      * path. If a class path resource is found, that resource is used. If no class path resource is found, an attempt is
472      * made to parse the location value to an URL. On successful parsing, that URL is used. Otherwise the location value
473      * is interpreted as a file name relative to the base directory of the project. If that file exists, that file is
474      * used. If nothing is found at the given location, depending on the optional flag, a warning message is logged or a
475      * build failure is produced.
476      * </p>
477      * <p>
478      * The optional flag is used to flag the resource optional. When an optional resource is not found, a warning
479      * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false
480      * </p>
481      * <p>
482      * The format value is used to specify the format of the properties resource. Supported values are {@code plain}
483      * and {@code xml}.<br/><b>Default value is:</b> plain
484      * </p>
485      * <p>
486      * The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening
487      * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/>
488      * <b>Default value is:</b> 60000
489      * </p>
490      * <p>
491      * The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource.
492      * A timeout of zero is interpreted as an infinite timeout.<br/>
493      * <b>Default value is:</b> 60000
494      * </p>
495      *
496      * @parameter
497      * @since 1.2
498      */
499     private List<TemplateParameterResource> templateParameterResources;
500 
501     /**
502      * Global transformation parameters.
503      * <pre>
504      * &lt;transformationParameters>
505      *   &lt;transformationParameter>
506      *     &lt;key>The name of the parameter.&lt;/key>
507      *     &lt;value>The value of the parameter.&lt;/value>
508      *     &lt;type>The name of the class of the parameter's object.&lt;/type>
509      *   &lt;/transformationParameter>
510      * &lt;/transformationParameters>
511      * </pre>
512      *
513      * @parameter
514      * @since 1.2
515      */
516     private List<TransformationParameter> transformationParameters;
517 
518     /**
519      * Global transformation output properties.
520      * <pre>
521      * &lt;transformationOutputProperties>
522      *   &lt;transformationOutputProperty>
523      *     &lt;key>The name of the property.&lt;/key>
524      *     &lt;value>The value of the property.&lt;/value>
525      *     &lt;type>The name of the class of the properties object.&lt;/type>
526      *   &lt;/transformationOutputProperty>
527      * &lt;/transformationOutputProperties>
528      * </pre>
529      *
530      * @parameter
531      * @since 1.2
532      */
533     private List<TransformationOutputProperty> transformationOutputProperties;
534 
535     /**
536      * Global transformation parameter resources.
537      * <pre>
538      * &lt;transformationParameterResources>
539      *   &lt;transformationParameterResource>
540      *     &lt;location>The location of the properties resource.&lt;/location>
541      *     &lt;optional>Flag indicating the properties resource is optional.&lt;/optional>
542      *     &lt;format>The format of the properties resource.&lt;/format>
543      *     &lt;connectTimeout>Timeout value, in milliseconds.&lt;/connectTimeout>
544      *     &lt;readTimeout>Timeout value, in milliseconds.&lt;/readTimeout>
545      *   &lt;/transformationParameterResource>
546      * &lt;/transformationParameterResources>
547      * </pre>
548      * <p>
549      * The location value is used to first search the class path of the plugin and the project's main or test class
550      * path. If a class path resource is found, that resource is used. If no class path resource is found, an attempt is
551      * made to parse the location value to an URL. On successful parsing, that URL is used. Otherwise the location value
552      * is interpreted as a file name relative to the base directory of the project. If that file exists, that file is
553      * used. If nothing is found at the given location, depending on the optional flag, a warning message is logged or a
554      * build failure is produced.
555      * </p>
556      * <p>
557      * The optional flag is used to flag the resource optional. When an optional resource is not found, a warning
558      * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false
559      * </p>
560      * <p>
561      * The format value is used to specify the format of the properties resource. Supported values are {@code plain}
562      * and {@code xml}.<br/><b>Default value is:</b> plain
563      * </p>
564      * <p>
565      * The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening
566      * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/>
567      * <b>Default value is:</b> 60000
568      * </p>
569      * <p>
570      * The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource.
571      * A timeout of zero is interpreted as an infinite timeout.<br/>
572      * <b>Default value is:</b> 60000
573      * </p>
574      *
575      * @parameter
576      * @since 1.2
577      */
578     private List<TransformationParameterResource> transformationParameterResources;
579 
580     /**
581      * Class name of the {@code ClassFileProcessor} backing the goal.
582      *
583      * @parameter default-value="org.jomc.tools.ClassFileProcessor" expression="${jomc.classFileProcessorClassName}"
584      * @since 1.2
585      */
586     private String classFileProcessorClassName;
587 
588     /**
589      * Class name of the {@code ResourceFileProcessor} backing the goal.
590      *
591      * @parameter default-value="org.jomc.tools.ResourceFileProcessor"
592      * expression="${jomc.resourceFileProcessorClassName}"
593      * @since 1.2
594      */
595     private String resourceFileProcessorClassName;
596 
597     /**
598      * Class name of the {@code SourceFileProcessor} backing the goal.
599      *
600      * @parameter default-value="org.jomc.tools.SourceFileProcessor" expression="${jomc.sourceFileProcessorClassName}"
601      * @since 1.2
602      */
603     private String sourceFileProcessorClassName;
604 
605     /**
606      * {@code ModelContext} attributes.
607      * <pre>
608      * &lt;modelContextAttributes>
609      *   &lt;modelContextAttribute>
610      *     &lt;key>The name of the attribute.&lt;/key>
611      *     &lt;value>The value of the attribute.&lt;/value>
612      *     &lt;type>The name of the class of the attributes's object.&lt;/type>
613      *   &lt;/modelContextAttribute>
614      * &lt;/modelContextAttributes>
615      * </pre>
616      *
617      * @parameter
618      * @since 1.2
619      */
620     private List<ModelContextAttribute> modelContextAttributes;
621 
622     /**
623      * Flag controlling JAXP schema validation of model resources.
624      *
625      * @parameter default-value="true" expression="${jomc.modelResourceValidationEnabled}"
626      *
627      * @since 1.2
628      */
629     private boolean modelResourceValidationEnabled;
630 
631     /**
632      * Flag controlling JAXP schema validation of modlet resources.
633      *
634      * @parameter default-value="true" expression="${jomc.modletResourceValidationEnabled}"
635      *
636      * @since 1.2
637      */
638     private boolean modletResourceValidationEnabled;
639 
640     /**
641      * Flag controlling Java validation.
642      *
643      * @parameter default-value="true" expression="${jomc.javaValidationEnabled}"
644      *
645      * @since 1.4
646      */
647     private boolean javaValidationEnabled;
648 
649     /**
650      * Names of modlets to exclude.
651      *
652      * @parameter expression="${jomc.modletExcludes}"
653      *
654      * @since 1.6
655      */
656     private List<String> modletExcludes;
657 
658     /**
659      * Names of modlets to include.
660      *
661      * @parameter expression="${jomc.modletIncludes}"
662      *
663      * @since 1.6
664      */
665     private List<String> modletIncludes;
666 
667     /**
668      * The Maven project of the instance.
669      *
670      * @parameter expression="${project}"
671      * @required
672      * @readonly
673      */
674     private MavenProject mavenProject;
675 
676     /**
677      * List of plugin artifacts.
678      *
679      * @parameter expression="${plugin.artifacts}"
680      * @required
681      * @readonly
682      */
683     private List<Artifact> pluginArtifacts;
684 
685     /**
686      * The Maven session of the instance.
687      *
688      * @parameter expression="${session}"
689      * @required
690      * @readonly
691      * @since 1.1
692      */
693     private MavenSession mavenSession;
694 
695     /**
696      * Creates a new {@code AbstractJomcMojo} instance.
697      */
698     public AbstractJomcMojo()
699     {
700         super();
701     }
702 
703     /**
704      * {@inheritDoc}
705      *
706      * @see #assertValidParameters()
707      * @see #isExecutionPermitted()
708      * @see #executeTool()
709      */
710     @SuppressWarnings( "deprecation" )
711     public void execute() throws MojoExecutionException, MojoFailureException
712     {
713         this.assertValidParameters();
714 
715         try
716         {
717             this.logSeparator();
718 
719             if ( this.isLoggable( Level.INFO ) )
720             {
721                 this.log( Level.INFO, Messages.getMessage( "title" ), null );
722             }
723 
724             if ( this.isExecutionPermitted() )
725             {
726                 this.executeTool();
727             }
728             else if ( this.isLoggable( Level.INFO ) )
729             {
730                 this.log( Level.INFO, Messages.getMessage( "executionSuppressed", this.getExecutionStrategy() ), null );
731             }
732         }
733         catch ( final Exception e )
734         {
735             throw new MojoExecutionException( Messages.getMessage( e ), e );
736         }
737         finally
738         {
739             JomcTool.setDefaultTemplateProfile( null );
740             this.logSeparator();
741         }
742     }
743 
744     /**
745      * Validates the parameters of the goal.
746      *
747      * @throws MojoFailureException if illegal parameter values are detected.
748      *
749      * @see #assertValidResources(java.util.Collection)
750      * @since 1.2
751      */
752     protected void assertValidParameters() throws MojoFailureException
753     {
754         this.assertValidResources( this.templateParameterResources );
755         this.assertValidResources( this.transformationParameterResources );
756         this.assertValidResources( this.velocityPropertyResources );
757     }
758 
759     /**
760      * Validates a given resource collection.
761      *
762      * @param resources The resource collection to validate or {@code null}.
763      *
764      * @throws MojoFailureException if a location property of a given resource holds a {@code null} value or a given
765      * {@code PropertiesResourceType} holds an illegal format.
766      *
767      * @see #assertValidParameters()
768      * @see PropertiesResourceType#isFormatSupported(java.lang.String)
769      * @since 1.2
770      */
771     protected final void assertValidResources( final Collection<? extends ResourceType> resources )
772         throws MojoFailureException
773     {
774         if ( resources != null )
775         {
776             for ( final ResourceType r : resources )
777             {
778                 if ( r.getLocation() == null )
779                 {
780                     throw new MojoFailureException( Messages.getMessage( "mandatoryParameter", "location" ) );
781                 }
782 
783                 if ( r instanceof PropertiesResourceType )
784                 {
785                     final PropertiesResourceType p = (PropertiesResourceType) r;
786 
787                     if ( !PropertiesResourceType.isFormatSupported( p.getFormat() ) )
788                     {
789                         throw new MojoFailureException( Messages.getMessage(
790                             "illegalPropertiesFormat", p.getFormat(),
791                             StringUtils.join( PropertiesResourceType.getSupportedFormats(), ',' ) ) );
792 
793                     }
794                 }
795             }
796         }
797     }
798 
799     /**
800      * Executes this tool.
801      *
802      * @throws Exception if execution of this tool fails.
803      */
804     protected abstract void executeTool() throws Exception;
805 
806     /**
807      * Gets the goal of the instance.
808      *
809      * @return The goal of the instance.
810      *
811      * @throws MojoExecutionException if getting the goal of the instance fails.
812      * @since 1.1
813      */
814     protected abstract String getGoal() throws MojoExecutionException;
815 
816     /**
817      * Gets the execution strategy of the instance.
818      *
819      * @return The execution strategy of the instance.
820      *
821      * @throws MojoExecutionException if getting the execution strategy of the instance fails.
822      * @since 1.1
823      */
824     protected abstract String getExecutionStrategy() throws MojoExecutionException;
825 
826     /**
827      * Gets a flag indicating the current execution is permitted.
828      *
829      * @return {@code true}, if the current execution is permitted; {@code false}, if the current execution is
830      * suppressed.
831      *
832      * @throws MojoExecutionException if getting the flag fails.
833      *
834      * @since 1.1
835      * @see #getGoal()
836      * @see #getExecutionStrategy()
837      */
838     protected boolean isExecutionPermitted() throws MojoExecutionException
839     {
840         try
841         {
842             boolean permitted = true;
843 
844             if ( MojoDescriptor.SINGLE_PASS_EXEC_STRATEGY.equals( this.getExecutionStrategy() ) )
845             {
846                 final File flagFile =
847                     new File( this.getSessionDirectory(),
848                               ArtifactUtils.versionlessKey( this.getMavenProject().getArtifact() ).hashCode()
849                                   + "-" + this.getGoal()
850                                   + "-" + this.getMavenSession().getStartTime().getTime() + ".flg" );
851 
852                 if ( !this.getSessionDirectory().exists() && !this.getSessionDirectory().mkdirs() )
853                 {
854                     throw new MojoExecutionException( Messages.getMessage(
855                         "failedCreatingDirectory", this.getSessionDirectory().getAbsolutePath() ) );
856 
857                 }
858 
859                 permitted = flagFile.createNewFile();
860             }
861 
862             return permitted;
863         }
864         catch ( final IOException e )
865         {
866             throw new MojoExecutionException( Messages.getMessage( e ), e );
867         }
868     }
869 
870     /**
871      * Gets the Maven project of the instance.
872      *
873      * @return The Maven project of the instance.
874      *
875      * @throws MojoExecutionException if getting the Maven project of the instance fails.
876      */
877     protected MavenProject getMavenProject() throws MojoExecutionException
878     {
879         return this.mavenProject;
880     }
881 
882     /**
883      * Gets the Maven session of the instance.
884      *
885      * @return The Maven session of the instance.
886      *
887      * @throws MojoExecutionException if getting the Maven session of the instance fails.
888      *
889      * @since 1.1
890      */
891     protected MavenSession getMavenSession() throws MojoExecutionException
892     {
893         return this.mavenSession;
894     }
895 
896     /**
897      * Gets an absolute {@code File} instance for a given name.
898      * <p>
899      * This method constructs a new {@code File} instance using the given name. If the resulting file is not
900      * absolute, the value of the {@code basedir} property of the current Maven project is prepended.
901      * </p>
902      *
903      * @param name The name to get an absolute {@code File} instance for.
904      *
905      * @return An absolute {@code File} instance constructed from {@code name}.
906      *
907      * @throws MojoExecutionException if getting an absolute {@code File} instance for {@code name} fails.
908      * @throws NullPointerException if {@code name} is {@code null}.
909      *
910      * @since 1.1
911      */
912     protected File getAbsoluteFile( final String name ) throws MojoExecutionException
913     {
914         if ( name == null )
915         {
916             throw new NullPointerException( "name" );
917         }
918 
919         File file = new File( name );
920         if ( !file.isAbsolute() )
921         {
922             file = new File( this.getMavenProject().getBasedir(), name );
923         }
924 
925         return file;
926     }
927 
928     /**
929      * Gets the directory holding the compiled class files of the project.
930      *
931      * @return The directory holding the compiled class files of the project.
932      *
933      * @throws MojoExecutionException if getting the directory fails.
934      *
935      * @since 1.1
936      */
937     protected File getOutputDirectory() throws MojoExecutionException
938     {
939         if ( this.classesDirectory != null )
940         {
941             if ( this.isLoggable( Level.WARNING ) )
942             {
943                 this.log( Level.WARNING, Messages.getMessage(
944                           "deprecationWarning", "classesDirectory", "outputDirectory" ), null );
945 
946             }
947 
948             if ( !this.classesDirectory.equals( this.outputDirectory ) )
949             {
950                 if ( this.isLoggable( Level.WARNING ) )
951                 {
952                     this.log( Level.WARNING, Messages.getMessage( "ignoringParameter", "outputDirectory" ), null );
953                 }
954 
955                 this.outputDirectory = this.classesDirectory;
956             }
957 
958             this.classesDirectory = null;
959         }
960 
961         final File dir = this.getAbsoluteFile( this.outputDirectory );
962         if ( !dir.exists() && !dir.mkdirs() )
963         {
964             throw new MojoExecutionException( Messages.getMessage( "failedCreatingDirectory", dir.getAbsolutePath() ) );
965         }
966 
967         return dir;
968     }
969 
970     /**
971      * Gets the directory holding the compiled test class files of the project.
972      *
973      * @return The directory holding the compiled test class files of the project.
974      *
975      * @throws MojoExecutionException if getting the directory fails.
976      *
977      * @since 1.1
978      */
979     protected File getTestOutputDirectory() throws MojoExecutionException
980     {
981         if ( this.testClassesDirectory != null )
982         {
983             if ( this.isLoggable( Level.WARNING ) )
984             {
985                 this.log( Level.WARNING, Messages.getMessage(
986                           "deprecationWarning", "testClassesDirectory", "testOutputDirectory" ), null );
987 
988             }
989 
990             if ( !this.testClassesDirectory.equals( this.testOutputDirectory ) )
991             {
992                 if ( this.isLoggable( Level.WARNING ) )
993                 {
994                     this.log( Level.WARNING, Messages.getMessage( "ignoringParameter", "testOutputDirectory" ), null );
995                 }
996 
997                 this.testOutputDirectory = this.testClassesDirectory;
998             }
999 
1000             this.testClassesDirectory = null;
1001         }
1002 
1003         final File dir = this.getAbsoluteFile( this.testOutputDirectory );
1004         if ( !dir.exists() && !dir.mkdirs() )
1005         {
1006             throw new MojoExecutionException( Messages.getMessage( "failedCreatingDirectory", dir.getAbsolutePath() ) );
1007         }
1008 
1009         return dir;
1010     }
1011 
1012     /**
1013      * Gets the directory holding the source files of the project.
1014      *
1015      * @return The directory holding the source files of the project.
1016      *
1017      * @throws MojoExecutionException if getting the directory fails.
1018      *
1019      * @since 1.1
1020      */
1021     protected File getSourceDirectory() throws MojoExecutionException
1022     {
1023         return this.getAbsoluteFile( this.sourceDirectory );
1024     }
1025 
1026     /**
1027      * Gets the directory holding the test source files of the project.
1028      *
1029      * @return The directory holding the test source files of the project.
1030      *
1031      * @throws MojoExecutionException if getting the directory fails.
1032      *
1033      * @since 1.1
1034      */
1035     protected File getTestSourceDirectory() throws MojoExecutionException
1036     {
1037         return this.getAbsoluteFile( this.testSourceDirectory );
1038     }
1039 
1040     /**
1041      * Gets the directory holding the session related files of the project.
1042      *
1043      * @return The directory holding the session related files of the project.
1044      *
1045      * @throws MojoExecutionException if getting the directory fails.
1046      *
1047      * @since 1.1
1048      */
1049     protected File getSessionDirectory() throws MojoExecutionException
1050     {
1051         return this.getAbsoluteFile( this.sessionDirectory );
1052     }
1053 
1054     /**
1055      * Gets the directory holding the reports of the project.
1056      *
1057      * @return The directory holding the reports of the project.
1058      *
1059      * @throws MojoExecutionException if getting the directory fails.
1060      *
1061      * @since 1.1
1062      */
1063     protected File getReportOutputDirectory() throws MojoExecutionException
1064     {
1065         return this.getAbsoluteFile( this.reportOutputDirectory );
1066     }
1067 
1068     /**
1069      * Gets the project's runtime class loader of the instance.
1070      *
1071      * @return The project's runtime class loader of the instance.
1072      *
1073      * @throws MojoExecutionException if getting the class loader fails.
1074      */
1075     protected ClassLoader getMainClassLoader() throws MojoExecutionException
1076     {
1077         try
1078         {
1079             final Set<String> mainClasspathElements = this.getMainClasspathElements();
1080             final Set<URI> uris = new HashSet<URI>( mainClasspathElements.size() );
1081 
1082             for ( final String element : mainClasspathElements )
1083             {
1084                 final URI uri = new File( element ).toURI();
1085                 if ( !uris.contains( uri ) )
1086                 {
1087                     uris.add( uri );
1088                 }
1089             }
1090 
1091             if ( this.isLoggable( Level.FINEST ) )
1092             {
1093                 this.log( Level.FINEST, Messages.getMessage( "mainClasspathInfo" ), null );
1094             }
1095 
1096             int i = 0;
1097             final URL[] urls = new URL[ uris.size() ];
1098             for ( final URI uri : uris )
1099             {
1100                 urls[i++] = uri.toURL();
1101 
1102                 if ( this.isLoggable( Level.FINEST ) )
1103                 {
1104                     this.log( Level.FINEST, "\t" + urls[i - 1].toExternalForm(), null );
1105                 }
1106             }
1107 
1108             return new URLClassLoader( urls, Thread.currentThread().getContextClassLoader() );
1109         }
1110         catch ( final IOException e )
1111         {
1112             throw new MojoExecutionException( Messages.getMessage( e ), e );
1113         }
1114     }
1115 
1116     /**
1117      * Gets the project's test class loader of the instance.
1118      *
1119      * @return The project's test class loader of the instance.
1120      *
1121      * @throws MojoExecutionException if getting the class loader fails.
1122      */
1123     protected ClassLoader getTestClassLoader() throws MojoExecutionException
1124     {
1125         try
1126         {
1127             final Set<String> testClasspathElements = this.getTestClasspathElements();
1128             final Set<URI> uris = new HashSet<URI>( testClasspathElements.size() );
1129 
1130             for ( final String element : testClasspathElements )
1131             {
1132                 final URI uri = new File( element ).toURI();
1133                 if ( !uris.contains( uri ) )
1134                 {
1135                     uris.add( uri );
1136                 }
1137             }
1138 
1139             if ( this.isLoggable( Level.FINEST ) )
1140             {
1141                 this.log( Level.FINEST, Messages.getMessage( "testClasspathInfo" ), null );
1142             }
1143 
1144             int i = 0;
1145             final URL[] urls = new URL[ uris.size() ];
1146             for ( final URI uri : uris )
1147             {
1148                 urls[i++] = uri.toURL();
1149 
1150                 if ( this.isLoggable( Level.FINEST ) )
1151                 {
1152                     this.log( Level.FINEST, "\t" + urls[i - 1].toExternalForm(), null );
1153                 }
1154             }
1155 
1156             return new URLClassLoader( urls, Thread.currentThread().getContextClassLoader() );
1157         }
1158         catch ( final IOException e )
1159         {
1160             throw new MojoExecutionException( Messages.getMessage( e ), e );
1161         }
1162     }
1163 
1164     /**
1165      * Gets the project's runtime class path elements.
1166      *
1167      * @return A set of class path element strings.
1168      *
1169      * @throws MojoExecutionException if getting the class path elements fails.
1170      */
1171     protected Set<String> getMainClasspathElements() throws MojoExecutionException
1172     {
1173         final List<?> runtimeArtifacts = this.getMavenProject().getRuntimeArtifacts();
1174         final List<?> compileArtifacts = this.getMavenProject().getCompileArtifacts();
1175         final Set<String> elements = new HashSet<String>( runtimeArtifacts.size() + compileArtifacts.size() + 1 );
1176         elements.add( this.getOutputDirectory().getAbsolutePath() );
1177 
1178         for ( final Iterator<?> it = runtimeArtifacts.iterator(); it.hasNext(); )
1179         {
1180             final Artifact a = (Artifact) it.next();
1181             final Artifact pluginArtifact = this.getPluginArtifact( a );
1182 
1183             if ( a.getFile() == null )
1184             {
1185                 if ( this.isLoggable( Level.WARNING ) )
1186                 {
1187                     this.log( Level.WARNING, Messages.getMessage( "ignoringArtifact", a.toString() ), null );
1188                 }
1189 
1190                 continue;
1191             }
1192 
1193             if ( pluginArtifact != null )
1194             {
1195                 if ( this.isLoggable( Level.FINER ) )
1196                 {
1197                     this.log( Level.FINER, Messages.getMessage(
1198                               "ignoringPluginArtifact", a.toString(), pluginArtifact.toString() ), null );
1199 
1200                 }
1201 
1202                 continue;
1203             }
1204 
1205             final String element = a.getFile().getAbsolutePath();
1206             elements.add( element );
1207         }
1208 
1209         for ( final Iterator<?> it = compileArtifacts.iterator(); it.hasNext(); )
1210         {
1211             final Artifact a = (Artifact) it.next();
1212             final Artifact pluginArtifact = this.getPluginArtifact( a );
1213 
1214             if ( a.getFile() == null )
1215             {
1216                 if ( this.isLoggable( Level.WARNING ) )
1217                 {
1218                     this.log( Level.WARNING, Messages.getMessage( "ignoringArtifact", a.toString() ), null );
1219                 }
1220 
1221                 continue;
1222             }
1223 
1224             if ( pluginArtifact != null )
1225             {
1226                 if ( this.isLoggable( Level.FINER ) )
1227                 {
1228                     this.log( Level.FINER, Messages.getMessage(
1229                               "ignoringPluginArtifact", a.toString(), pluginArtifact.toString() ), null );
1230 
1231                 }
1232 
1233                 continue;
1234             }
1235 
1236             final String element = a.getFile().getAbsolutePath();
1237             elements.add( element );
1238         }
1239 
1240         return elements;
1241     }
1242 
1243     /**
1244      * Gets the project's test class path elements.
1245      *
1246      * @return A set of class path element strings.
1247      *
1248      * @throws MojoExecutionException if getting the class path elements fails.
1249      */
1250     protected Set<String> getTestClasspathElements() throws MojoExecutionException
1251     {
1252         final List<?> testArtifacts = this.getMavenProject().getTestArtifacts();
1253         final Set<String> elements = new HashSet<String>( testArtifacts.size() + 2 );
1254         elements.add( this.getOutputDirectory().getAbsolutePath() );
1255         elements.add( this.getTestOutputDirectory().getAbsolutePath() );
1256 
1257         for ( final Iterator<?> it = testArtifacts.iterator(); it.hasNext(); )
1258         {
1259             final Artifact a = (Artifact) it.next();
1260             final Artifact pluginArtifact = this.getPluginArtifact( a );
1261 
1262             if ( a.getFile() == null )
1263             {
1264                 if ( this.isLoggable( Level.WARNING ) )
1265                 {
1266                     this.log( Level.WARNING, Messages.getMessage( "ignoringArtifact", a.toString() ), null );
1267                 }
1268 
1269                 continue;
1270             }
1271 
1272             if ( pluginArtifact != null )
1273             {
1274                 if ( this.isLoggable( Level.FINER ) )
1275                 {
1276                     this.log( Level.FINER, Messages.getMessage(
1277                               "ignoringPluginArtifact", a.toString(), pluginArtifact.toString() ), null );
1278 
1279                 }
1280 
1281                 continue;
1282             }
1283 
1284             final String element = a.getFile().getAbsolutePath();
1285             elements.add( element );
1286         }
1287 
1288         return elements;
1289     }
1290 
1291     /**
1292      * Gets a flag indicating verbose output is enabled.
1293      *
1294      * @return {@code true}, if verbose output is enabled; {@code false}, if information messages are suppressed.
1295      *
1296      * @throws MojoExecutionException if getting the flag fails.
1297      *
1298      * @since 1.1
1299      */
1300     protected final boolean isVerbose() throws MojoExecutionException
1301     {
1302         return this.verbose;
1303     }
1304 
1305     /**
1306      * Sets the flag indicating verbose output is enabled.
1307      *
1308      * @param value {@code true}, to enable verbose output; {@code false}, to suppress information messages.
1309      *
1310      * @throws MojoExecutionException if setting the flag fails.
1311      *
1312      * @since 1.1
1313      */
1314     protected final void setVerbose( final boolean value ) throws MojoExecutionException
1315     {
1316         this.verbose = value;
1317     }
1318 
1319     /**
1320      * Gets a flag indicating the processing of sources is enabled.
1321      *
1322      * @return {@code true}, if processing of sources is enabled; {@code false}, else.
1323      *
1324      * @throws MojoExecutionException if getting the flag fails.
1325      */
1326     protected final boolean isSourceProcessingEnabled() throws MojoExecutionException
1327     {
1328         return this.sourceProcessingEnabled;
1329     }
1330 
1331     /**
1332      * Sets the flag indicating the processing of sources is enabled.
1333      *
1334      * @param value {@code true}, to enable processing of sources; {@code false}, to disable processing of sources.
1335      *
1336      * @throws MojoExecutionException if setting the flag fails.
1337      *
1338      * @since 1.1
1339      */
1340     protected final void setSourceProcessingEnabled( final boolean value ) throws MojoExecutionException
1341     {
1342         this.sourceProcessingEnabled = value;
1343     }
1344 
1345     /**
1346      * Gets a flag indicating the processing of resources is enabled.
1347      *
1348      * @return {@code true}, if processing of resources is enabled; {@code false}, else.
1349      *
1350      * @throws MojoExecutionException if getting the flag fails.
1351      */
1352     protected final boolean isResourceProcessingEnabled() throws MojoExecutionException
1353     {
1354         return this.resourceProcessingEnabled;
1355     }
1356 
1357     /**
1358      * Sets the flag indicating the processing of resources is enabled.
1359      *
1360      * @param value {@code true}, to enable processing of resources; {@code false}, to disable processing of resources.
1361      *
1362      * @throws MojoExecutionException if setting the flag fails.
1363      *
1364      * @since 1.1
1365      */
1366     protected final void setResourceProcessingEnabled( final boolean value ) throws MojoExecutionException
1367     {
1368         this.resourceProcessingEnabled = value;
1369     }
1370 
1371     /**
1372      * Gets a flag indicating the processing of classes is enabled.
1373      *
1374      * @return {@code true}, if processing of classes is enabled; {@code false}, else.
1375      *
1376      * @throws MojoExecutionException if getting the flag fails.
1377      */
1378     protected final boolean isClassProcessingEnabled() throws MojoExecutionException
1379     {
1380         return this.classProcessingEnabled;
1381     }
1382 
1383     /**
1384      * Sets the flag indicating the processing of classes is enabled.
1385      *
1386      * @param value {@code true}, to enable processing of classes; {@code false}, to disable processing of classes.
1387      *
1388      * @throws MojoExecutionException if setting the flag fails.
1389      *
1390      * @since 1.1
1391      */
1392     protected final void setClassProcessingEnabled( final boolean value ) throws MojoExecutionException
1393     {
1394         this.classProcessingEnabled = value;
1395     }
1396 
1397     /**
1398      * Gets a flag indicating the processing of models is enabled.
1399      *
1400      * @return {@code true}, if processing of models is enabled; {@code false}, else.
1401      *
1402      * @throws MojoExecutionException if getting the flag fails.
1403      */
1404     protected final boolean isModelProcessingEnabled() throws MojoExecutionException
1405     {
1406         return this.modelProcessingEnabled;
1407     }
1408 
1409     /**
1410      * Sets the flag indicating the processing of models is enabled.
1411      *
1412      * @param value {@code true}, to enable processing of models; {@code false}, to disable processing of models.
1413      *
1414      * @throws MojoExecutionException if setting the flag fails.
1415      *
1416      * @since 1.1
1417      */
1418     protected final void setModelProcessingEnabled( final boolean value ) throws MojoExecutionException
1419     {
1420         this.modelProcessingEnabled = value;
1421     }
1422 
1423     /**
1424      * Gets a flag indicating model object class path resolution is enabled.
1425      *
1426      * @return {@code true}, if model object class path resolution is enabled; {@code false}, else.
1427      *
1428      * @throws MojoExecutionException if getting the flag fails.
1429      */
1430     protected final boolean isModelObjectClasspathResolutionEnabled() throws MojoExecutionException
1431     {
1432         return this.modelObjectClasspathResolutionEnabled;
1433     }
1434 
1435     /**
1436      * Sets the flag indicating model object class path resolution is enabled.
1437      *
1438      * @param value {@code true}, to enable model object class path resolution; {@code false}, to disable model object
1439      * class path resolution.
1440      *
1441      * @throws MojoExecutionException if setting the flag fails.
1442      *
1443      * @since 1.1
1444      */
1445     protected final void setModelObjectClasspathResolutionEnabled( final boolean value ) throws MojoExecutionException
1446     {
1447         this.modelObjectClasspathResolutionEnabled = value;
1448     }
1449 
1450     /**
1451      * Gets the identifier of the model to process.
1452      *
1453      * @return The identifier of the model to process.
1454      *
1455      * @throws MojoExecutionException if getting the identifier fails.
1456      */
1457     protected String getModel() throws MojoExecutionException
1458     {
1459         return this.model;
1460     }
1461 
1462     /**
1463      * Gets the name of the module to process.
1464      *
1465      * @return The name of the module to process.
1466      *
1467      * @throws MojoExecutionException if getting the name of the module fails.
1468      */
1469     protected String getModuleName() throws MojoExecutionException
1470     {
1471         return this.moduleName;
1472     }
1473 
1474     /**
1475      * Gets the name of the test module to process.
1476      *
1477      * @return The name of the test module to process.
1478      *
1479      * @throws MojoExecutionException if getting the name of the test module fails.
1480      */
1481     protected String getTestModuleName() throws MojoExecutionException
1482     {
1483         return this.testModuleName;
1484     }
1485 
1486     /**
1487      * Gets the model to process.
1488      *
1489      * @param context The model context to get the model to process with.
1490      *
1491      * @return The model to process.
1492      *
1493      * @throws NullPointerException if {@code context} is {@code null}.
1494      * @throws MojoExecutionException if getting the model fails.
1495      */
1496     protected Model getModel( final ModelContext context ) throws MojoExecutionException
1497     {
1498         if ( context == null )
1499         {
1500             throw new NullPointerException( "context" );
1501         }
1502 
1503         try
1504         {
1505             Model m = context.findModel( this.getModel() );
1506             final Modules modules = ModelHelper.getModules( m );
1507 
1508             if ( modules != null && this.isModelObjectClasspathResolutionEnabled() )
1509             {
1510                 final Module classpathModule =
1511                     modules.getClasspathModule( Modules.getDefaultClasspathModuleName(), context.getClassLoader() );
1512 
1513                 if ( classpathModule != null )
1514                 {
1515                     modules.getModule().add( classpathModule );
1516                 }
1517             }
1518 
1519             if ( this.isModelProcessingEnabled() )
1520             {
1521                 m = context.processModel( m );
1522             }
1523 
1524             return m;
1525         }
1526         catch ( final ModelException e )
1527         {
1528             throw new MojoExecutionException( Messages.getMessage( e ), e );
1529         }
1530     }
1531 
1532     /**
1533      * Creates a new model context instance for a given class loader.
1534      *
1535      * @param classLoader The class loader to use for creating the context.
1536      *
1537      * @return A new model context instance for {@code classLoader}.
1538      *
1539      * @throws MojoExecutionException if creating the model context fails.
1540      *
1541      * @see #setupModelContext(org.jomc.modlet.ModelContext)
1542      */
1543     protected ModelContext createModelContext( final ClassLoader classLoader ) throws MojoExecutionException
1544     {
1545         final ModelContextFactory modelContextFactory;
1546         if ( this.modelContextFactoryClassName != null )
1547         {
1548             modelContextFactory = ModelContextFactory.newInstance( this.modelContextFactoryClassName );
1549         }
1550         else
1551         {
1552             modelContextFactory = ModelContextFactory.newInstance();
1553         }
1554 
1555         final ModelContext context = modelContextFactory.newModelContext( classLoader );
1556         this.setupModelContext( context );
1557 
1558         return context;
1559     }
1560 
1561     /**
1562      * Creates a new tool instance for processing source files.
1563      *
1564      * @param context The context of the tool.
1565      *
1566      * @return A new tool instance for processing source files.
1567      *
1568      * @throws NullPointerException if {@code context} is {@code null}.
1569      * @throws MojoExecutionException if creating a new tool instance fails.
1570      *
1571      * @see #createJomcTool(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class)
1572      */
1573     protected SourceFileProcessor createSourceFileProcessor( final ModelContext context ) throws MojoExecutionException
1574     {
1575         if ( context == null )
1576         {
1577             throw new NullPointerException( "context" );
1578         }
1579 
1580         return this.createJomcTool( context, this.sourceFileProcessorClassName, SourceFileProcessor.class );
1581     }
1582 
1583     /**
1584      * Creates a new tool instance for processing resource files.
1585      *
1586      * @param context The context of the tool.
1587      *
1588      * @return A new tool instance for processing resource files.
1589      *
1590      * @throws NullPointerException if {@code context} is {@code null}.
1591      * @throws MojoExecutionException if creating a new tool instance fails.
1592      *
1593      * @see #createJomcTool(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class)
1594      */
1595     protected ResourceFileProcessor createResourceFileProcessor( final ModelContext context )
1596         throws MojoExecutionException
1597     {
1598         if ( context == null )
1599         {
1600             throw new NullPointerException( "context" );
1601         }
1602 
1603         return this.createJomcTool( context, this.resourceFileProcessorClassName, ResourceFileProcessor.class );
1604     }
1605 
1606     /**
1607      * Creates a new tool instance for processing class files.
1608      *
1609      * @param context The context of the tool.
1610      *
1611      * @return A new tool instance for processing class files.
1612      *
1613      * @throws NullPointerException if {@code context} is {@code null}.
1614      * @throws MojoExecutionException if creating a new tool instance fails.
1615      *
1616      * @see #createJomcTool(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class)
1617      */
1618     protected ClassFileProcessor createClassFileProcessor( final ModelContext context ) throws MojoExecutionException
1619     {
1620         if ( context == null )
1621         {
1622             throw new NullPointerException( "context" );
1623         }
1624 
1625         return this.createJomcTool( context, this.classFileProcessorClassName, ClassFileProcessor.class );
1626     }
1627 
1628     /**
1629      * Creates a new {@code JomcTool} object for a given class name and type.
1630      *
1631      * @param context The context of the tool.
1632      * @param className The name of the class to create an object of.
1633      * @param type The class of the type of object to create.
1634      * @param <T> The type of the object to create.
1635      *
1636      * @return A new instance of the class with name {@code className}.
1637      *
1638      * @throws NullPointerException if {@code context}, {@code className} or {@code type} is {@code null}.
1639      * @throws MojoExecutionException if creating a new {@code JomcTool} object fails.
1640      *
1641      * @see #createObject(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class)
1642      * @see #setupJomcTool(org.jomc.modlet.ModelContext, org.jomc.tools.JomcTool)
1643      *
1644      * @since 1.2
1645      */
1646     protected <T extends JomcTool> T createJomcTool( final ModelContext context, final String className,
1647                                                      final Class<T> type ) throws MojoExecutionException
1648     {
1649         if ( context == null )
1650         {
1651             throw new NullPointerException( "context" );
1652         }
1653         if ( className == null )
1654         {
1655             throw new NullPointerException( "className" );
1656         }
1657         if ( type == null )
1658         {
1659             throw new NullPointerException( "type" );
1660         }
1661 
1662         final T tool = this.createObject( context, className, type );
1663         this.setupJomcTool( context, tool );
1664         return tool;
1665     }
1666 
1667     /**
1668      * Creates a new object for a given class name and type.
1669      *
1670      * @param className The name of the class to create an object of.
1671      * @param type The class of the type of object to create.
1672      * @param <T> The type of the object to create.
1673      *
1674      * @return A new instance of the class with name {@code className}.
1675      *
1676      * @throws NullPointerException if {@code className} or {@code type} is {@code null}.
1677      * @throws MojoExecutionException if creating a new object fails.
1678      *
1679      * @since 1.2
1680      * @deprecated As of JOMC 1.8, replaced by method {@link #createObject(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class)}.
1681      * This method will be removed in JOMC 2.0.
1682      */
1683     @Deprecated
1684     @SuppressWarnings( "deprecation" )
1685     protected <T> T createObject( final String className, final Class<T> type ) throws MojoExecutionException
1686     {
1687         if ( className == null )
1688         {
1689             throw new NullPointerException( "className" );
1690         }
1691         if ( type == null )
1692         {
1693             throw new NullPointerException( "type" );
1694         }
1695 
1696         try
1697         {
1698             return Class.forName( className ).asSubclass( type ).newInstance();
1699         }
1700         catch ( final InstantiationException e )
1701         {
1702             throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1703         }
1704         catch ( final IllegalAccessException e )
1705         {
1706             throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1707         }
1708         catch ( final ClassNotFoundException e )
1709         {
1710             throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1711         }
1712         catch ( final ClassCastException e )
1713         {
1714             throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1715         }
1716     }
1717 
1718     /**
1719      * Creates a new object for a given class name and type.
1720      *
1721      * @param modelContext The model context to search.
1722      * @param className The name of the class to create an object of.
1723      * @param type The class of the type of object to create.
1724      * @param <T> The type of the object to create.
1725      *
1726      * @return A new instance of the class with name {@code className}.
1727      *
1728      * @throws NullPointerException if {@code modelContext}, {@code className} or {@code type} is {@code null}.
1729      * @throws MojoExecutionException if creating a new object fails.
1730      *
1731      * @since 1.8
1732      */
1733     protected <T> T createObject( final ModelContext modelContext, final String className, final Class<T> type )
1734         throws MojoExecutionException
1735     {
1736         if ( modelContext == null )
1737         {
1738             throw new NullPointerException( "modelContext" );
1739         }
1740         if ( className == null )
1741         {
1742             throw new NullPointerException( "className" );
1743         }
1744         if ( type == null )
1745         {
1746             throw new NullPointerException( "type" );
1747         }
1748 
1749         try
1750         {
1751             final Class<?> javaClass = modelContext.findClass( className );
1752 
1753             if ( javaClass == null )
1754             {
1755                 throw new MojoExecutionException( Messages.getMessage( "classNotFound", className ) );
1756             }
1757 
1758             return javaClass.asSubclass( type ).newInstance();
1759         }
1760         catch ( final ModelException e )
1761         {
1762             String m = Messages.getMessage( e );
1763             m = m == null ? "" : " " + m;
1764 
1765             throw new MojoExecutionException( Messages.getMessage( "failedSearchingClass", className, m ), e );
1766         }
1767         catch ( final InstantiationException e )
1768         {
1769             throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1770         }
1771         catch ( final IllegalAccessException e )
1772         {
1773             throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1774         }
1775         catch ( final ClassCastException e )
1776         {
1777             throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e );
1778         }
1779     }
1780 
1781     /**
1782      * Creates an {@code URL} for a given resource location.
1783      * <p>
1784      * This method first searches the class path of the plugin for a single resource matching {@code location}. If
1785      * such a resource is found, the URL of that resource is returned. If no such resource is found, an attempt is made
1786      * to parse the given location to an URL. On successful parsing, that URL is returned. Failing that, the given
1787      * location is interpreted as a file name relative to the project's base directory. If that file is found, the URL
1788      * of that file is returned. Otherwise {@code null} is returned.
1789      * </p>
1790      *
1791      * @param location The location to create an {@code URL} from.
1792      *
1793      * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and
1794      * {@code location} points to a non-existent resource.
1795      *
1796      * @throws NullPointerException if {@code location} is {@code null}.
1797      * @throws MojoExecutionException if creating an URL fails.
1798      *
1799      * @since 1.2
1800      * @deprecated As of JOMC 1.8, replaced by method {@link #getResource(org.jomc.modlet.ModelContext, java.lang.String)}.
1801      * This method will be removed in JOMC 2.0.
1802      */
1803     @Deprecated
1804     @SuppressWarnings( "deprecation" )
1805     protected URL getResource( final String location ) throws MojoExecutionException
1806     {
1807         if ( location == null )
1808         {
1809             throw new NullPointerException( "location" );
1810         }
1811 
1812         try
1813         {
1814             String absolute = location;
1815             if ( !absolute.startsWith( "/" ) )
1816             {
1817                 absolute = "/" + location;
1818             }
1819 
1820             URL resource = this.getClass().getResource( absolute );
1821             if ( resource == null )
1822             {
1823                 try
1824                 {
1825                     resource = new URL( location );
1826                 }
1827                 catch ( final MalformedURLException e )
1828                 {
1829                     if ( this.isLoggable( Level.FINEST ) )
1830                     {
1831                         this.log( Level.FINEST, Messages.getMessage( e ), e );
1832                     }
1833 
1834                     resource = null;
1835                 }
1836             }
1837 
1838             if ( resource == null )
1839             {
1840                 final File f = this.getAbsoluteFile( location );
1841 
1842                 if ( f.isFile() )
1843                 {
1844                     resource = f.toURI().toURL();
1845                 }
1846             }
1847 
1848             return resource;
1849         }
1850         catch ( final MalformedURLException e )
1851         {
1852             String m = Messages.getMessage( e );
1853             m = m == null ? "" : " " + m;
1854 
1855             throw new MojoExecutionException( Messages.getMessage( "malformedLocation", location, m ), e );
1856         }
1857     }
1858 
1859     /**
1860      * Creates an {@code URL} for a given resource location.
1861      * <p>
1862      * This method first searches the given model context for a single resource matching {@code location}. If such a
1863      * resource is found, the URL of that resource is returned. If no such resource is found, an attempt is made to
1864      * parse the given location to an URL. On successful parsing, that URL is returned. Failing that, the given location
1865      * is interpreted as a file name relative to the project's base directory. If that file is found, the URL of that
1866      * file is returned. Otherwise {@code null} is returned.
1867      * </p>
1868      *
1869      * @param modelContext The model conext to search.
1870      * @param location The location to create an {@code URL} from.
1871      *
1872      * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and
1873      * {@code location} points to a non-existent resource.
1874      *
1875      * @throws NullPointerException if {@code modelContext} or {@code location} is {@code null}.
1876      * @throws MojoExecutionException if creating an URL fails.
1877      *
1878      * @since 1.8
1879      */
1880     protected URL getResource( final ModelContext modelContext, final String location ) throws MojoExecutionException
1881     {
1882         if ( modelContext == null )
1883         {
1884             throw new NullPointerException( "modelContext" );
1885         }
1886         if ( location == null )
1887         {
1888             throw new NullPointerException( "location" );
1889         }
1890 
1891         try
1892         {
1893             String absolute = location;
1894             if ( !absolute.startsWith( "/" ) )
1895             {
1896                 absolute = "/" + location;
1897             }
1898 
1899             URL resource = modelContext.findResource( absolute );
1900 
1901             if ( resource == null )
1902             {
1903                 try
1904                 {
1905                     resource = new URL( location );
1906                 }
1907                 catch ( final MalformedURLException e )
1908                 {
1909                     if ( this.isLoggable( Level.FINEST ) )
1910                     {
1911                         this.log( Level.FINEST, Messages.getMessage( e ), e );
1912                     }
1913 
1914                     resource = null;
1915                 }
1916             }
1917 
1918             if ( resource == null )
1919             {
1920                 final File f = this.getAbsoluteFile( location );
1921 
1922                 if ( f.isFile() )
1923                 {
1924                     resource = f.toURI().toURL();
1925                 }
1926             }
1927 
1928             return resource;
1929         }
1930         catch ( final ModelException e )
1931         {
1932             String m = Messages.getMessage( e );
1933             m = m == null ? "" : " " + m;
1934 
1935             throw new MojoExecutionException( Messages.getMessage( "failedSearchingResource", location, m ), e );
1936         }
1937         catch ( final MalformedURLException e )
1938         {
1939             String m = Messages.getMessage( e );
1940             m = m == null ? "" : " " + m;
1941 
1942             throw new MojoExecutionException( Messages.getMessage( "malformedLocation", location, m ), e );
1943         }
1944     }
1945 
1946     /**
1947      * Creates an {@code URL} for a given directory location.
1948      * <p>
1949      * This method first attempts to parse the given location to an URL. On successful parsing, that URL is returned.
1950      * Failing that, the given location is interpreted as a directory name relative to the project's base directory.
1951      * If that directory is found, the URL of that directory is returned. Otherwise {@code null} is returned.
1952      * </p>
1953      *
1954      * @param location The directory location to create an {@code URL} from.
1955      *
1956      * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and
1957      * {@code location} points to a non-existent directory.
1958      *
1959      * @throws NullPointerException if {@code location} is {@code null}.
1960      * @throws MojoExecutionException if creating an URL fails.
1961      *
1962      * @since 1.2
1963      */
1964     protected URL getDirectory( final String location ) throws MojoExecutionException
1965     {
1966         if ( location == null )
1967         {
1968             throw new NullPointerException( "location" );
1969         }
1970 
1971         try
1972         {
1973             URL resource = null;
1974 
1975             try
1976             {
1977                 resource = new URL( location );
1978             }
1979             catch ( final MalformedURLException e )
1980             {
1981                 if ( this.isLoggable( Level.FINEST ) )
1982                 {
1983                     this.log( Level.FINEST, Messages.getMessage( e ), e );
1984                 }
1985 
1986                 resource = null;
1987             }
1988 
1989             if ( resource == null )
1990             {
1991                 final File f = this.getAbsoluteFile( location );
1992 
1993                 if ( f.isDirectory() )
1994                 {
1995                     resource = f.toURI().toURL();
1996                 }
1997             }
1998 
1999             return resource;
2000         }
2001         catch ( final MalformedURLException e )
2002         {
2003             String m = Messages.getMessage( e );
2004             m = m == null ? "" : " " + m;
2005 
2006             throw new MojoExecutionException( Messages.getMessage( "malformedLocation", location, m ), e );
2007         }
2008     }
2009 
2010     /**
2011      * Creates a new {@code Transformer} from a given {@code TransformerResourceType}.
2012      *
2013      * @param resource The resource to initialize the transformer with.
2014      *
2015      * @return A {@code Transformer} for {@code resource} or {@code null}, if {@code resource} is not found and flagged
2016      * optional.
2017      *
2018      * @throws NullPointerException if {@code resource} is {@code null}.
2019      * @throws MojoExecutionException if creating a transformer fails.
2020      *
2021      * @see #getResource(java.lang.String)
2022      * @since 1.2
2023      * @deprecated As of JOMC 1.8, replaced by method {@link #getTransformer(org.jomc.modlet.ModelContext, org.jomc.mojo.TransformerResourceType)}.
2024      * This method will be removed in JOMC 2.0.
2025      */
2026     @Deprecated
2027     @SuppressWarnings( "deprecation" )
2028     protected Transformer getTransformer( final TransformerResourceType resource ) throws MojoExecutionException
2029     {
2030         if ( resource == null )
2031         {
2032             throw new NullPointerException( "resource" );
2033         }
2034 
2035         InputStream in = null;
2036         boolean suppressExceptionOnClose = true;
2037         final URL url = this.getResource( resource.getLocation() );
2038         final ErrorListener errorListener = new ErrorListener()
2039         {
2040 
2041             public void warning( final TransformerException exception ) throws TransformerException
2042             {
2043                 try
2044                 {
2045                     log( Level.WARNING, Messages.getMessage( exception ), exception );
2046                 }
2047                 catch ( final MojoExecutionException e )
2048                 {
2049                     getLog().warn( exception );
2050                     getLog().error( e );
2051                 }
2052             }
2053 
2054             public void error( final TransformerException exception ) throws TransformerException
2055             {
2056                 try
2057                 {
2058                     log( Level.SEVERE, Messages.getMessage( exception ), exception );
2059                 }
2060                 catch ( final MojoExecutionException e )
2061                 {
2062                     getLog().error( exception );
2063                     getLog().error( e );
2064                 }
2065 
2066                 throw exception;
2067             }
2068 
2069             public void fatalError( final TransformerException exception ) throws TransformerException
2070             {
2071                 try
2072                 {
2073                     log( Level.SEVERE, Messages.getMessage( exception ), exception );
2074                 }
2075                 catch ( final MojoExecutionException e )
2076                 {
2077                     getLog().error( exception );
2078                     getLog().error( e );
2079                 }
2080 
2081                 throw exception;
2082             }
2083 
2084         };
2085 
2086         try
2087         {
2088             if ( url != null )
2089             {
2090                 if ( this.isLoggable( Level.FINER ) )
2091                 {
2092                     this.log( Level.FINER, Messages.getMessage( "loadingTransformer", url.toExternalForm() ), null );
2093                 }
2094 
2095                 final URLConnection con = url.openConnection();
2096                 con.setConnectTimeout( resource.getConnectTimeout() );
2097                 con.setReadTimeout( resource.getReadTimeout() );
2098                 con.connect();
2099                 in = con.getInputStream();
2100 
2101                 final TransformerFactory transformerFactory = TransformerFactory.newInstance();
2102                 transformerFactory.setErrorListener( errorListener );
2103                 final Transformer transformer =
2104                     transformerFactory.newTransformer( new StreamSource( in, url.toURI().toASCIIString() ) );
2105 
2106                 transformer.setErrorListener( errorListener );
2107 
2108                 for ( final Map.Entry<Object, Object> e : System.getProperties().entrySet() )
2109                 {
2110                     transformer.setParameter( e.getKey().toString(), e.getValue() );
2111                 }
2112 
2113                 if ( this.getMavenProject().getProperties() != null )
2114                 {
2115                     for ( final Map.Entry<Object, Object> e : this.getMavenProject().getProperties().entrySet() )
2116                     {
2117                         transformer.setParameter( e.getKey().toString(), e.getValue() );
2118                     }
2119                 }
2120 
2121                 if ( this.transformationParameterResources != null )
2122                 {
2123                     for ( int i = 0, s0 = this.transformationParameterResources.size(); i < s0; i++ )
2124                     {
2125                         for ( final Map.Entry<Object, Object> e : this.getProperties(
2126                             this.transformationParameterResources.get( i ) ).entrySet() )
2127                         {
2128                             transformer.setParameter( e.getKey().toString(), e.getValue() );
2129                         }
2130                     }
2131                 }
2132 
2133                 if ( this.transformationParameters != null )
2134                 {
2135                     for ( final TransformationParameter e : this.transformationParameters )
2136                     {
2137                         transformer.setParameter( e.getKey(), e.getObject() );
2138                     }
2139                 }
2140 
2141                 if ( this.transformationOutputProperties != null )
2142                 {
2143                     for ( final TransformationOutputProperty e : this.transformationOutputProperties )
2144                     {
2145                         transformer.setOutputProperty( e.getKey(), e.getValue() );
2146                     }
2147                 }
2148 
2149                 for ( int i = 0, s0 = resource.getTransformationParameterResources().size(); i < s0; i++ )
2150                 {
2151                     for ( final Map.Entry<Object, Object> e : this.getProperties(
2152                         resource.getTransformationParameterResources().get( i ) ).entrySet() )
2153                     {
2154                         transformer.setParameter( e.getKey().toString(), e.getValue() );
2155                     }
2156                 }
2157 
2158                 for ( final TransformationParameter e : resource.getTransformationParameters() )
2159                 {
2160                     transformer.setParameter( e.getKey(), e.getObject() );
2161                 }
2162 
2163                 for ( final TransformationOutputProperty e : resource.getTransformationOutputProperties() )
2164                 {
2165                     transformer.setOutputProperty( e.getKey(), e.getValue() );
2166                 }
2167 
2168                 suppressExceptionOnClose = false;
2169                 return transformer;
2170             }
2171             else if ( resource.isOptional() )
2172             {
2173                 if ( this.isLoggable( Level.WARNING ) )
2174                 {
2175                     this.log( Level.WARNING, Messages.getMessage(
2176                               "transformerNotFound", resource.getLocation() ), null );
2177 
2178                 }
2179             }
2180             else
2181             {
2182                 throw new MojoExecutionException( Messages.getMessage(
2183                     "transformerNotFound", resource.getLocation() ) );
2184 
2185             }
2186         }
2187         catch ( final InstantiationException e )
2188         {
2189             throw new MojoExecutionException( Messages.getMessage( e ), e );
2190         }
2191         catch ( final URISyntaxException e )
2192         {
2193             throw new MojoExecutionException( Messages.getMessage( e ), e );
2194         }
2195         catch ( final TransformerConfigurationException e )
2196         {
2197             String m = Messages.getMessage( e );
2198             if ( m == null )
2199             {
2200                 m = Messages.getMessage( e.getException() );
2201             }
2202 
2203             m = m == null ? "" : " " + m;
2204 
2205             throw new MojoExecutionException( Messages.getMessage(
2206                 "failedCreatingTransformer", resource.getLocation(), m ), e );
2207 
2208         }
2209         catch ( final SocketTimeoutException e )
2210         {
2211             String m = Messages.getMessage( e );
2212             m = m == null ? "" : " " + m;
2213 
2214             if ( resource.isOptional() )
2215             {
2216                 if ( this.isLoggable( Level.WARNING ) )
2217                 {
2218                     this.log( Level.WARNING, Messages.getMessage(
2219                               "failedLoadingTransformer", url.toExternalForm(), m ), e );
2220 
2221                 }
2222             }
2223             else
2224             {
2225                 throw new MojoExecutionException( Messages.getMessage(
2226                     "failedLoadingTransformer", url.toExternalForm(), m ), e );
2227 
2228             }
2229         }
2230         catch ( final IOException e )
2231         {
2232             String m = Messages.getMessage( e );
2233             m = m == null ? "" : " " + m;
2234 
2235             if ( resource.isOptional() )
2236             {
2237                 if ( this.isLoggable( Level.WARNING ) )
2238                 {
2239                     this.log( Level.WARNING, Messages.getMessage(
2240                               "failedLoadingTransformer", url.toExternalForm(), m ), e );
2241 
2242                 }
2243             }
2244             else
2245             {
2246                 throw new MojoExecutionException( Messages.getMessage(
2247                     "failedLoadingTransformer", url.toExternalForm(), m ), e );
2248 
2249             }
2250         }
2251         finally
2252         {
2253             try
2254             {
2255                 if ( in != null )
2256                 {
2257                     in.close();
2258                 }
2259             }
2260             catch ( final IOException e )
2261             {
2262                 if ( suppressExceptionOnClose )
2263                 {
2264                     this.getLog().error( e );
2265                 }
2266                 else
2267                 {
2268                     throw new MojoExecutionException( Messages.getMessage( e ), e );
2269                 }
2270             }
2271         }
2272 
2273         return null;
2274     }
2275 
2276     /**
2277      * Creates a new {@code Transformer} from a given {@code TransformerResourceType}.
2278      *
2279      * @param modelContext The model context to search.
2280      * @param resource The resource to initialize the transformer with.
2281      *
2282      * @return A {@code Transformer} for {@code resource} or {@code null}, if {@code resource} is not found and flagged
2283      * optional.
2284      *
2285      * @throws NullPointerException if {@code modelContext} or {@code resource} is {@code null}.
2286      * @throws MojoExecutionException if creating a transformer fails.
2287      *
2288      * @see #getResource(org.jomc.modlet.ModelContext, java.lang.String)
2289      * @since 1.8
2290      */
2291     protected Transformer getTransformer( final ModelContext modelContext, final TransformerResourceType resource )
2292         throws MojoExecutionException
2293     {
2294         if ( modelContext == null )
2295         {
2296             throw new NullPointerException( "modelContext" );
2297         }
2298         if ( resource == null )
2299         {
2300             throw new NullPointerException( "resource" );
2301         }
2302 
2303         InputStream in = null;
2304         boolean suppressExceptionOnClose = true;
2305         final URL url = this.getResource( modelContext, resource.getLocation() );
2306         final ErrorListener errorListener = new ErrorListener()
2307         {
2308 
2309             public void warning( final TransformerException exception ) throws TransformerException
2310             {
2311                 try
2312                 {
2313                     log( Level.WARNING, Messages.getMessage( exception ), exception );
2314                 }
2315                 catch ( final MojoExecutionException e )
2316                 {
2317                     getLog().warn( exception );
2318                     getLog().error( e );
2319                 }
2320             }
2321 
2322             public void error( final TransformerException exception ) throws TransformerException
2323             {
2324                 try
2325                 {
2326                     log( Level.SEVERE, Messages.getMessage( exception ), exception );
2327                 }
2328                 catch ( final MojoExecutionException e )
2329                 {
2330                     getLog().error( exception );
2331                     getLog().error( e );
2332                 }
2333 
2334                 throw exception;
2335             }
2336 
2337             public void fatalError( final TransformerException exception ) throws TransformerException
2338             {
2339                 try
2340                 {
2341                     log( Level.SEVERE, Messages.getMessage( exception ), exception );
2342                 }
2343                 catch ( final MojoExecutionException e )
2344                 {
2345                     getLog().error( exception );
2346                     getLog().error( e );
2347                 }
2348 
2349                 throw exception;
2350             }
2351 
2352         };
2353 
2354         try
2355         {
2356             if ( url != null )
2357             {
2358                 if ( this.isLoggable( Level.FINER ) )
2359                 {
2360                     this.log( Level.FINER, Messages.getMessage( "loadingTransformer", url.toExternalForm() ), null );
2361                 }
2362 
2363                 final URLConnection con = url.openConnection();
2364                 con.setConnectTimeout( resource.getConnectTimeout() );
2365                 con.setReadTimeout( resource.getReadTimeout() );
2366                 con.connect();
2367                 in = con.getInputStream();
2368 
2369                 final TransformerFactory transformerFactory = TransformerFactory.newInstance();
2370                 transformerFactory.setErrorListener( errorListener );
2371                 final Transformer transformer =
2372                     transformerFactory.newTransformer( new StreamSource( in, url.toURI().toASCIIString() ) );
2373 
2374                 transformer.setErrorListener( errorListener );
2375 
2376                 for ( final Map.Entry<Object, Object> e : System.getProperties().entrySet() )
2377                 {
2378                     transformer.setParameter( e.getKey().toString(), e.getValue() );
2379                 }
2380 
2381                 if ( this.getMavenProject().getProperties() != null )
2382                 {
2383                     for ( final Map.Entry<Object, Object> e : this.getMavenProject().getProperties().entrySet() )
2384                     {
2385                         transformer.setParameter( e.getKey().toString(), e.getValue() );
2386                     }
2387                 }
2388 
2389                 if ( this.transformationParameterResources != null )
2390                 {
2391                     for ( int i = 0, s0 = this.transformationParameterResources.size(); i < s0; i++ )
2392                     {
2393                         for ( final Map.Entry<Object, Object> e : this.getProperties(
2394                             modelContext, this.transformationParameterResources.get( i ) ).entrySet() )
2395                         {
2396                             transformer.setParameter( e.getKey().toString(), e.getValue() );
2397                         }
2398                     }
2399                 }
2400 
2401                 if ( this.transformationParameters != null )
2402                 {
2403                     for ( final TransformationParameter e : this.transformationParameters )
2404                     {
2405                         transformer.setParameter( e.getKey(), e.getObject( modelContext ) );
2406                     }
2407                 }
2408 
2409                 if ( this.transformationOutputProperties != null )
2410                 {
2411                     for ( final TransformationOutputProperty e : this.transformationOutputProperties )
2412                     {
2413                         transformer.setOutputProperty( e.getKey(), e.getValue() );
2414                     }
2415                 }
2416 
2417                 for ( int i = 0, s0 = resource.getTransformationParameterResources().size(); i < s0; i++ )
2418                 {
2419                     for ( final Map.Entry<Object, Object> e : this.getProperties(
2420                         modelContext, resource.getTransformationParameterResources().get( i ) ).entrySet() )
2421                     {
2422                         transformer.setParameter( e.getKey().toString(), e.getValue() );
2423                     }
2424                 }
2425 
2426                 for ( final TransformationParameter e : resource.getTransformationParameters() )
2427                 {
2428                     transformer.setParameter( e.getKey(), e.getObject( modelContext ) );
2429                 }
2430 
2431                 for ( final TransformationOutputProperty e : resource.getTransformationOutputProperties() )
2432                 {
2433                     transformer.setOutputProperty( e.getKey(), e.getValue() );
2434                 }
2435 
2436                 suppressExceptionOnClose = false;
2437                 return transformer;
2438             }
2439             else if ( resource.isOptional() )
2440             {
2441                 if ( this.isLoggable( Level.WARNING ) )
2442                 {
2443                     this.log( Level.WARNING, Messages.getMessage(
2444                               "transformerNotFound", resource.getLocation() ), null );
2445 
2446                 }
2447             }
2448             else
2449             {
2450                 throw new MojoExecutionException( Messages.getMessage(
2451                     "transformerNotFound", resource.getLocation() ) );
2452 
2453             }
2454         }
2455         catch ( final InstantiationException e )
2456         {
2457             throw new MojoExecutionException( Messages.getMessage( e ), e );
2458         }
2459         catch ( final URISyntaxException e )
2460         {
2461             throw new MojoExecutionException( Messages.getMessage( e ), e );
2462         }
2463         catch ( final TransformerConfigurationException e )
2464         {
2465             String m = Messages.getMessage( e );
2466             if ( m == null )
2467             {
2468                 m = Messages.getMessage( e.getException() );
2469             }
2470 
2471             m = m == null ? "" : " " + m;
2472 
2473             throw new MojoExecutionException( Messages.getMessage(
2474                 "failedCreatingTransformer", resource.getLocation(), m ), e );
2475 
2476         }
2477         catch ( final SocketTimeoutException e )
2478         {
2479             String m = Messages.getMessage( e );
2480             m = m == null ? "" : " " + m;
2481 
2482             if ( resource.isOptional() )
2483             {
2484                 if ( this.isLoggable( Level.WARNING ) )
2485                 {
2486                     this.log( Level.WARNING, Messages.getMessage(
2487                               "failedLoadingTransformer", url.toExternalForm(), m ), e );
2488 
2489                 }
2490             }
2491             else
2492             {
2493                 throw new MojoExecutionException( Messages.getMessage(
2494                     "failedLoadingTransformer", url.toExternalForm(), m ), e );
2495 
2496             }
2497         }
2498         catch ( final IOException e )
2499         {
2500             String m = Messages.getMessage( e );
2501             m = m == null ? "" : " " + m;
2502 
2503             if ( resource.isOptional() )
2504             {
2505                 if ( this.isLoggable( Level.WARNING ) )
2506                 {
2507                     this.log( Level.WARNING, Messages.getMessage(
2508                               "failedLoadingTransformer", url.toExternalForm(), m ), e );
2509 
2510                 }
2511             }
2512             else
2513             {
2514                 throw new MojoExecutionException( Messages.getMessage(
2515                     "failedLoadingTransformer", url.toExternalForm(), m ), e );
2516 
2517             }
2518         }
2519         finally
2520         {
2521             try
2522             {
2523                 if ( in != null )
2524                 {
2525                     in.close();
2526                 }
2527             }
2528             catch ( final IOException e )
2529             {
2530                 if ( suppressExceptionOnClose )
2531                 {
2532                     this.getLog().error( e );
2533                 }
2534                 else
2535                 {
2536                     throw new MojoExecutionException( Messages.getMessage( e ), e );
2537                 }
2538             }
2539         }
2540 
2541         return null;
2542     }
2543 
2544     /**
2545      * Creates a new {@code Properties} instance from a {@code PropertiesResourceType}.
2546      *
2547      * @param propertiesResourceType The {@code PropertiesResourceType} specifying the properties to create.
2548      *
2549      * @return The properties for {@code propertiesResourceType}.
2550      *
2551      * @throws NullPointerException if {@code propertiesResourceType} is {@code null}.
2552      * @throws MojoExecutionException if loading properties fails.
2553      *
2554      * @see #getResource(java.lang.String)
2555      * @since 1.2
2556      * @deprecated As of JOMC 1.8, replaced by method {@link #getProperties(org.jomc.modlet.ModelContext, org.jomc.mojo.PropertiesResourceType)}.
2557      * This method will be removed in JOMC 2.0.
2558      */
2559     @Deprecated
2560     @SuppressWarnings( "deprecation" )
2561     protected Properties getProperties( final PropertiesResourceType propertiesResourceType )
2562         throws MojoExecutionException
2563     {
2564         if ( propertiesResourceType == null )
2565         {
2566             throw new NullPointerException( "propertiesResourceType" );
2567         }
2568 
2569         InputStream in = null;
2570         boolean suppressExceptionOnClose = true;
2571         final URL url = this.getResource( propertiesResourceType.getLocation() );
2572         final Properties properties = new Properties();
2573 
2574         try
2575         {
2576             if ( url != null )
2577             {
2578                 if ( this.isLoggable( Level.FINER ) )
2579                 {
2580                     this.log( Level.FINER, Messages.getMessage( "loadingProperties", url.toExternalForm() ), null );
2581                 }
2582 
2583                 final URLConnection con = url.openConnection();
2584                 con.setConnectTimeout( propertiesResourceType.getConnectTimeout() );
2585                 con.setReadTimeout( propertiesResourceType.getReadTimeout() );
2586                 con.connect();
2587 
2588                 in = con.getInputStream();
2589 
2590                 if ( PropertiesResourceType.PLAIN_FORMAT.equalsIgnoreCase( propertiesResourceType.getFormat() ) )
2591                 {
2592                     properties.load( in );
2593                 }
2594                 else if ( PropertiesResourceType.XML_FORMAT.equalsIgnoreCase( propertiesResourceType.getFormat() ) )
2595                 {
2596                     properties.loadFromXML( in );
2597                 }
2598             }
2599             else if ( propertiesResourceType.isOptional() )
2600             {
2601                 if ( this.isLoggable( Level.WARNING ) )
2602                 {
2603                     this.log( Level.WARNING, Messages.getMessage(
2604                               "propertiesNotFound", propertiesResourceType.getLocation() ), null );
2605 
2606                 }
2607             }
2608             else
2609             {
2610                 throw new MojoExecutionException( Messages.getMessage(
2611                     "propertiesNotFound", propertiesResourceType.getLocation() ) );
2612 
2613             }
2614 
2615             suppressExceptionOnClose = false;
2616         }
2617         catch ( final SocketTimeoutException e )
2618         {
2619             String m = Messages.getMessage( e );
2620             m = m == null ? "" : " " + m;
2621 
2622             if ( propertiesResourceType.isOptional() )
2623             {
2624                 if ( this.isLoggable( Level.WARNING ) )
2625                 {
2626                     this.log( Level.WARNING, Messages.getMessage(
2627                               "failedLoadingProperties", url.toExternalForm(), m ), e );
2628 
2629                 }
2630             }
2631             else
2632             {
2633                 throw new MojoExecutionException( Messages.getMessage(
2634                     "failedLoadingProperties", url.toExternalForm(), m ), e );
2635 
2636             }
2637         }
2638         catch ( final IOException e )
2639         {
2640             String m = Messages.getMessage( e );
2641             m = m == null ? "" : " " + m;
2642 
2643             if ( propertiesResourceType.isOptional() )
2644             {
2645                 if ( this.isLoggable( Level.WARNING ) )
2646                 {
2647                     this.log( Level.WARNING, Messages.getMessage(
2648                               "failedLoadingProperties", url.toExternalForm(), m ), e );
2649 
2650                 }
2651             }
2652             else
2653             {
2654                 throw new MojoExecutionException( Messages.getMessage(
2655                     "failedLoadingProperties", url.toExternalForm(), m ), e );
2656 
2657             }
2658         }
2659         finally
2660         {
2661             try
2662             {
2663                 if ( in != null )
2664                 {
2665                     in.close();
2666                 }
2667             }
2668             catch ( final IOException e )
2669             {
2670                 if ( suppressExceptionOnClose )
2671                 {
2672                     this.getLog().error( e );
2673                 }
2674                 else
2675                 {
2676                     throw new MojoExecutionException( Messages.getMessage( e ), e );
2677                 }
2678             }
2679         }
2680 
2681         return properties;
2682     }
2683 
2684     /**
2685      * Creates a new {@code Properties} instance from a {@code PropertiesResourceType}.
2686      *
2687      * @param modelContext The model context to search.
2688      * @param propertiesResourceType The {@code PropertiesResourceType} specifying the properties to create.
2689      *
2690      * @return The properties for {@code propertiesResourceType}.
2691      *
2692      * @throws NullPointerException if {@code modelContext} or {@code propertiesResourceType} is {@code null}.
2693      * @throws MojoExecutionException if loading properties fails.
2694      *
2695      * @see #getResource(org.jomc.modlet.ModelContext, java.lang.String)
2696      * @since 1.8
2697      */
2698     protected Properties getProperties( final ModelContext modelContext,
2699                                         final PropertiesResourceType propertiesResourceType )
2700         throws MojoExecutionException
2701     {
2702         if ( modelContext == null )
2703         {
2704             throw new NullPointerException( "modelContext" );
2705         }
2706         if ( propertiesResourceType == null )
2707         {
2708             throw new NullPointerException( "propertiesResourceType" );
2709         }
2710 
2711         InputStream in = null;
2712         boolean suppressExceptionOnClose = true;
2713         final URL url = this.getResource( modelContext, propertiesResourceType.getLocation() );
2714         final Properties properties = new Properties();
2715 
2716         try
2717         {
2718             if ( url != null )
2719             {
2720                 if ( this.isLoggable( Level.FINER ) )
2721                 {
2722                     this.log( Level.FINER, Messages.getMessage( "loadingProperties", url.toExternalForm() ), null );
2723                 }
2724 
2725                 final URLConnection con = url.openConnection();
2726                 con.setConnectTimeout( propertiesResourceType.getConnectTimeout() );
2727                 con.setReadTimeout( propertiesResourceType.getReadTimeout() );
2728                 con.connect();
2729 
2730                 in = con.getInputStream();
2731 
2732                 if ( PropertiesResourceType.PLAIN_FORMAT.equalsIgnoreCase( propertiesResourceType.getFormat() ) )
2733                 {
2734                     properties.load( in );
2735                 }
2736                 else if ( PropertiesResourceType.XML_FORMAT.equalsIgnoreCase( propertiesResourceType.getFormat() ) )
2737                 {
2738                     properties.loadFromXML( in );
2739                 }
2740             }
2741             else if ( propertiesResourceType.isOptional() )
2742             {
2743                 if ( this.isLoggable( Level.WARNING ) )
2744                 {
2745                     this.log( Level.WARNING, Messages.getMessage(
2746                               "propertiesNotFound", propertiesResourceType.getLocation() ), null );
2747 
2748                 }
2749             }
2750             else
2751             {
2752                 throw new MojoExecutionException( Messages.getMessage(
2753                     "propertiesNotFound", propertiesResourceType.getLocation() ) );
2754 
2755             }
2756 
2757             suppressExceptionOnClose = false;
2758         }
2759         catch ( final SocketTimeoutException e )
2760         {
2761             String m = Messages.getMessage( e );
2762             m = m == null ? "" : " " + m;
2763 
2764             if ( propertiesResourceType.isOptional() )
2765             {
2766                 if ( this.isLoggable( Level.WARNING ) )
2767                 {
2768                     this.log( Level.WARNING, Messages.getMessage(
2769                               "failedLoadingProperties", url.toExternalForm(), m ), e );
2770 
2771                 }
2772             }
2773             else
2774             {
2775                 throw new MojoExecutionException( Messages.getMessage(
2776                     "failedLoadingProperties", url.toExternalForm(), m ), e );
2777 
2778             }
2779         }
2780         catch ( final IOException e )
2781         {
2782             String m = Messages.getMessage( e );
2783             m = m == null ? "" : " " + m;
2784 
2785             if ( propertiesResourceType.isOptional() )
2786             {
2787                 if ( this.isLoggable( Level.WARNING ) )
2788                 {
2789                     this.log( Level.WARNING, Messages.getMessage(
2790                               "failedLoadingProperties", url.toExternalForm(), m ), e );
2791 
2792                 }
2793             }
2794             else
2795             {
2796                 throw new MojoExecutionException( Messages.getMessage(
2797                     "failedLoadingProperties", url.toExternalForm(), m ), e );
2798 
2799             }
2800         }
2801         finally
2802         {
2803             try
2804             {
2805                 if ( in != null )
2806                 {
2807                     in.close();
2808                 }
2809             }
2810             catch ( final IOException e )
2811             {
2812                 if ( suppressExceptionOnClose )
2813                 {
2814                     this.getLog().error( e );
2815                 }
2816                 else
2817                 {
2818                     throw new MojoExecutionException( Messages.getMessage( e ), e );
2819                 }
2820             }
2821         }
2822 
2823         return properties;
2824     }
2825 
2826     /**
2827      * Tests if messages at a given level are logged.
2828      *
2829      * @param level The level to test.
2830      *
2831      * @return {@code true}, if messages at {@code level} are logged; {@code false}, if messages at {@code level} are
2832      * suppressed.
2833      *
2834      * @throws NullPointerException if {@code level} is {@code null}.
2835      * @throws MojoExecutionException if testing the level fails.
2836      *
2837      * @see #isVerbose()
2838      * @since 1.2
2839      */
2840     protected boolean isLoggable( final Level level ) throws MojoExecutionException
2841     {
2842         if ( level == null )
2843         {
2844             throw new NullPointerException( "level" );
2845         }
2846 
2847         boolean loggable = false;
2848 
2849         if ( level.intValue() <= Level.CONFIG.intValue() )
2850         {
2851             loggable = this.getLog().isDebugEnabled();
2852         }
2853         else if ( level.intValue() <= Level.INFO.intValue() )
2854         {
2855             loggable = this.getLog().isInfoEnabled() && this.isVerbose();
2856         }
2857         else if ( level.intValue() <= Level.WARNING.intValue() )
2858         {
2859             loggable = this.getLog().isWarnEnabled();
2860         }
2861         else if ( level.intValue() <= Level.SEVERE.intValue() )
2862         {
2863             loggable = this.getLog().isErrorEnabled();
2864         }
2865 
2866         return loggable;
2867     }
2868 
2869     /**
2870      * Logs a separator at a given level.
2871      *
2872      * @param level The level to log a separator at.
2873      *
2874      * @throws MojoExecutionException if logging fails.
2875      *
2876      * @deprecated As of JOMC 1.1, please use method {@link #logSeparator()}. This method will be removed in version
2877      * 2.0.
2878      */
2879     @Deprecated
2880     protected void logSeparator( final Level level ) throws MojoExecutionException
2881     {
2882         this.logSeparator();
2883     }
2884 
2885     /**
2886      * Logs a separator.
2887      *
2888      * @throws MojoExecutionException if logging fails.
2889      *
2890      * @since 1.1
2891      */
2892     protected void logSeparator() throws MojoExecutionException
2893     {
2894         if ( this.isLoggable( Level.INFO ) )
2895         {
2896             this.log( Level.INFO, Messages.getMessage( "separator" ), null );
2897         }
2898     }
2899 
2900     /**
2901      * Logs a message stating a tool is starting to process a module.
2902      *
2903      * @param toolName The tool starting execution.
2904      * @param module The module getting processed.
2905      *
2906      * @throws MojoExecutionException if logging fails.
2907      */
2908     protected void logProcessingModule( final String toolName, final String module ) throws MojoExecutionException
2909     {
2910         if ( this.isLoggable( Level.INFO ) )
2911         {
2912             this.log( Level.INFO, Messages.getMessage( "processingModule", toolName, module ), null );
2913         }
2914     }
2915 
2916     /**
2917      * Logs a message stating a tool is starting to process a model.
2918      *
2919      * @param toolName The tool starting execution.
2920      * @param model The model getting processed.
2921      *
2922      * @throws MojoExecutionException if logging fails.
2923      *
2924      * @since 1.1
2925      */
2926     protected void logProcessingModel( final String toolName, final String model ) throws MojoExecutionException
2927     {
2928         if ( this.isLoggable( Level.INFO ) )
2929         {
2930             this.log( Level.INFO, Messages.getMessage( "processingModel", toolName, model ), null );
2931         }
2932     }
2933 
2934     /**
2935      * Logs a message stating that a module has not been found.
2936      *
2937      * @param module The module not having been found.
2938      *
2939      * @throws MojoExecutionException if logging fails.
2940      */
2941     protected void logMissingModule( final String module ) throws MojoExecutionException
2942     {
2943         if ( this.isLoggable( Level.WARNING ) )
2944         {
2945             this.log( Level.WARNING, Messages.getMessage( "missingModule", module ), null );
2946         }
2947     }
2948 
2949     /**
2950      * Logs a message stating that a tool successfully completed execution.
2951      *
2952      * @param toolName The name of the tool.
2953      *
2954      * @throws MojoExecutionException if logging fails.
2955      */
2956     protected void logToolSuccess( final String toolName ) throws MojoExecutionException
2957     {
2958         if ( this.isLoggable( Level.INFO ) )
2959         {
2960             this.log( Level.INFO, Messages.getMessage( "toolSuccess", toolName ), null );
2961         }
2962     }
2963 
2964     /**
2965      * Logs a {@code ModelValidationReport}.
2966      *
2967      * @param context The context to use when marshalling detail elements of the report.
2968      * @param level The level to log at.
2969      * @param report The report to log.
2970      *
2971      * @throws MojoExecutionException if logging {@code report} fails.
2972      */
2973     protected void log( final ModelContext context, final Level level, final ModelValidationReport report )
2974         throws MojoExecutionException
2975     {
2976         try
2977         {
2978             if ( !report.getDetails().isEmpty() )
2979             {
2980                 this.logSeparator();
2981                 Marshaller marshaller = null;
2982 
2983                 for ( final ModelValidationReport.Detail detail : report.getDetails() )
2984                 {
2985                     this.log( detail.getLevel(), "o " + detail.getMessage(), null );
2986 
2987                     if ( detail.getElement() != null && this.isLoggable( Level.FINEST ) )
2988                     {
2989                         if ( marshaller == null )
2990                         {
2991                             marshaller = context.createMarshaller( this.getModel() );
2992                             marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
2993                         }
2994 
2995                         final StringWriter stringWriter = new StringWriter();
2996                         marshaller.marshal( detail.getElement(), stringWriter );
2997                         this.log( Level.FINEST, stringWriter.toString(), null );
2998                     }
2999                 }
3000             }
3001         }
3002         catch ( final ModelException e )
3003         {
3004             throw new MojoExecutionException( Messages.getMessage( e ), e );
3005         }
3006         catch ( final JAXBException e )
3007         {
3008             String message = Messages.getMessage( e );
3009             if ( message == null && e.getLinkedException() != null )
3010             {
3011                 message = Messages.getMessage( e.getLinkedException() );
3012             }
3013 
3014             throw new MojoExecutionException( message, e );
3015         }
3016     }
3017 
3018     /**
3019      * Logs a message and throwable at a given level.
3020      *
3021      * @param level The level to log at.
3022      * @param message The message to log or {@code null}.
3023      * @param throwable The throwable to log or {@code null}.
3024      *
3025      * @throws MojoExecutionException if logging fails.
3026      */
3027     protected void log( final Level level, final String message, final Throwable throwable )
3028         throws MojoExecutionException
3029     {
3030         BufferedReader reader = null;
3031         boolean suppressExceptionOnClose = true;
3032 
3033         try
3034         {
3035             if ( this.isLoggable( level ) )
3036             {
3037                 String line;
3038                 reader = new BufferedReader( new StringReader( message == null ? "" : message ) );
3039                 boolean throwableLogged = false;
3040 
3041                 while ( ( line = reader.readLine() ) != null )
3042                 {
3043                     final String mojoMessage =
3044                         Messages.getMessage( this.getLog().isDebugEnabled() ? "debugMessage" : "logMessage", line,
3045                                              Thread.currentThread().getName(), new Date( System.currentTimeMillis() ) );
3046 
3047                     if ( level.intValue() <= Level.CONFIG.intValue() )
3048                     {
3049                         this.getLog().debug( mojoMessage, throwableLogged ? null : throwable );
3050                     }
3051                     else if ( level.intValue() <= Level.INFO.intValue() )
3052                     {
3053                         this.getLog().info( mojoMessage, throwableLogged ? null : throwable );
3054                     }
3055                     else if ( level.intValue() <= Level.WARNING.intValue() )
3056                     {
3057                         this.getLog().warn( mojoMessage, throwableLogged ? null : throwable );
3058                     }
3059                     else if ( level.intValue() <= Level.SEVERE.intValue() )
3060                     {
3061                         this.getLog().error( mojoMessage, throwableLogged ? null : throwable );
3062                     }
3063 
3064                     throwableLogged = true;
3065                 }
3066             }
3067 
3068             suppressExceptionOnClose = false;
3069         }
3070         catch ( final IOException e )
3071         {
3072             this.getLog().error( e );
3073             throw new AssertionError( e );
3074         }
3075         finally
3076         {
3077             try
3078             {
3079                 if ( reader != null )
3080                 {
3081                     reader.close();
3082                 }
3083             }
3084             catch ( final IOException e )
3085             {
3086                 if ( !suppressExceptionOnClose )
3087                 {
3088                     throw new AssertionError( e );
3089                 }
3090             }
3091         }
3092     }
3093 
3094     /**
3095      * Configures a {@code ModelContext} instance.
3096      *
3097      * @param context The model context to configure.
3098      *
3099      * @throws NullPointerException if {@code context} is {@code null}.
3100      * @throws MojoExecutionException if configuring {@code context} fails.
3101      */
3102     protected void setupModelContext( final ModelContext context ) throws MojoExecutionException
3103     {
3104         if ( context == null )
3105         {
3106             throw new NullPointerException( "context" );
3107         }
3108 
3109         if ( this.isVerbose() || this.getLog().isDebugEnabled() )
3110         {
3111             context.setLogLevel( this.getLog().isDebugEnabled() ? Level.ALL : Level.INFO );
3112         }
3113 
3114         try
3115         {
3116             context.setModletSchemaSystemId( this.modletSchemaSystemId );
3117             context.getListeners().add( new ModelContext.Listener()
3118             {
3119 
3120                 @Override
3121                 public void onLog( final Level level, final String message, final Throwable t )
3122                 {
3123                     super.onLog( level, message, t );
3124 
3125                     try
3126                     {
3127                         log( level, message, t );
3128                     }
3129                     catch ( final MojoExecutionException e )
3130                     {
3131                         getLog().error( e );
3132                     }
3133                 }
3134 
3135             } );
3136 
3137             if ( this.providerLocation != null )
3138             {
3139                 context.setAttribute( DefaultModelContext.PROVIDER_LOCATION_ATTRIBUTE_NAME, this.providerLocation );
3140             }
3141 
3142             if ( this.platformProviderLocation != null )
3143             {
3144                 context.setAttribute( DefaultModelContext.PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME,
3145                                       this.platformProviderLocation );
3146 
3147             }
3148 
3149             if ( this.modletLocation != null )
3150             {
3151                 context.setAttribute( DefaultModletProvider.MODLET_LOCATION_ATTRIBUTE_NAME, this.modletLocation );
3152             }
3153 
3154             if ( this.transformerLocation != null )
3155             {
3156                 context.setAttribute( DefaultModelProcessor.TRANSFORMER_LOCATION_ATTRIBUTE_NAME,
3157                                       this.transformerLocation );
3158             }
3159 
3160             if ( this.moduleLocation != null )
3161             {
3162                 context.setAttribute( DefaultModelProvider.MODULE_LOCATION_ATTRIBUTE_NAME, this.moduleLocation );
3163             }
3164 
3165             context.setAttribute( ToolsModelProvider.MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME,
3166                                   this.modelObjectClasspathResolutionEnabled );
3167 
3168             context.setAttribute( ToolsModelProcessor.MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME,
3169                                   this.modelObjectClasspathResolutionEnabled );
3170 
3171             context.setAttribute( DefaultModletProvider.VALIDATING_ATTRIBUTE_NAME,
3172                                   this.modletResourceValidationEnabled );
3173 
3174             context.setAttribute( DefaultModelProvider.VALIDATING_ATTRIBUTE_NAME, this.modelResourceValidationEnabled );
3175             context.setAttribute( DefaultModelValidator.VALIDATE_JAVA_ATTRIBUTE_NAME, this.javaValidationEnabled );
3176 
3177             if ( this.modelContextAttributes != null )
3178             {
3179                 for ( final ModelContextAttribute e : this.modelContextAttributes )
3180                 {
3181                     final Object object = e.getObject( context );
3182 
3183                     if ( object != null )
3184                     {
3185                         context.setAttribute( e.getKey(), object );
3186                     }
3187                     else
3188                     {
3189                         context.clearAttribute( e.getKey() );
3190                     }
3191                 }
3192             }
3193 
3194             if ( ( this.modletIncludes != null && !this.modletIncludes.isEmpty() )
3195                      || ( this.modletExcludes != null && !this.modletExcludes.isEmpty() ) )
3196             {
3197                 final Modlets modlets = context.getModlets().clone();
3198 
3199                 for ( final Iterator<Modlet> it = modlets.getModlet().iterator(); it.hasNext(); )
3200                 {
3201                     final Modlet modlet = it.next();
3202 
3203                     if ( this.modletIncludes != null
3204                              && !this.modletIncludes.isEmpty()
3205                              && !this.modletIncludes.contains( modlet.getName() ) )
3206                     {
3207                         it.remove();
3208                         this.log( Level.INFO, Messages.getMessage( "excludingModlet", modlet.getName() ), null );
3209                         continue;
3210                     }
3211 
3212                     if ( this.modletExcludes != null
3213                              && !this.modletExcludes.isEmpty()
3214                              && this.modletExcludes.contains( modlet.getName() ) )
3215                     {
3216                         it.remove();
3217                         this.log( Level.INFO, Messages.getMessage( "excludingModlet", modlet.getName() ), null );
3218                         continue;
3219                     }
3220 
3221                     this.log( Level.INFO, Messages.getMessage( "includingModlet", modlet.getName() ), null );
3222                 }
3223 
3224                 context.setModlets( modlets );
3225             }
3226         }
3227         catch ( final InstantiationException e )
3228         {
3229             throw new MojoExecutionException( Messages.getMessage( e ), e );
3230         }
3231         catch ( final ModelException e )
3232         {
3233             throw new MojoExecutionException( Messages.getMessage( e ), e );
3234         }
3235     }
3236 
3237     /**
3238      * Configures a {@code JomcTool} instance.
3239      *
3240      * @param context The model context to use for configuring {@code tool}.
3241      * @param tool The tool to configure.
3242      *
3243      * @throws NullPointerException if {@code context} of {@code tool} is {@code null}.
3244      * @throws MojoExecutionException if configuring {@code tool} fails.
3245      */
3246     @SuppressWarnings( "deprecation" )
3247     protected void setupJomcTool( final ModelContext context, final JomcTool tool ) throws MojoExecutionException
3248     {
3249         if ( context == null )
3250         {
3251             throw new NullPointerException( "context" );
3252         }
3253         if ( tool == null )
3254         {
3255             throw new NullPointerException( "tool" );
3256         }
3257 
3258         try
3259         {
3260             if ( this.isVerbose() || this.getLog().isDebugEnabled() )
3261             {
3262                 tool.setLogLevel( this.getLog().isDebugEnabled() ? Level.ALL : Level.INFO );
3263             }
3264 
3265             tool.getListeners().add( new JomcTool.Listener()
3266             {
3267 
3268                 @Override
3269                 public void onLog( final Level level, final String message, final Throwable t )
3270                 {
3271                     super.onLog( level, message, t );
3272 
3273                     try
3274                     {
3275                         log( level, message, t );
3276                     }
3277                     catch ( final MojoExecutionException e )
3278                     {
3279                         getLog().error( e );
3280                     }
3281                 }
3282 
3283             } );
3284 
3285             if ( this.templateEncoding != null )
3286             {
3287                 if ( this.isLoggable( Level.WARNING ) )
3288                 {
3289                     this.log( Level.WARNING, Messages.getMessage(
3290                               "deprecationWarning", "templateEncoding", "defaultTemplateEncoding" ), null );
3291 
3292                 }
3293 
3294                 tool.setDefaultTemplateEncoding( this.templateEncoding );
3295             }
3296             else
3297             {
3298                 tool.setDefaultTemplateEncoding( this.defaultTemplateEncoding );
3299             }
3300 
3301             tool.setInputEncoding( this.sourceEncoding );
3302             tool.setOutputEncoding( this.sourceEncoding );
3303             tool.setDefaultTemplateProfile( this.defaultTemplateProfile );
3304             tool.setTemplateProfile( this.templateProfile );
3305             tool.setModel( this.getModel( context ) );
3306 
3307             if ( this.indentation != null )
3308             {
3309                 tool.setIndentation( StringEscapeUtils.unescapeJava( this.indentation ) );
3310             }
3311 
3312             if ( this.lineSeparator != null )
3313             {
3314                 tool.setLineSeparator( StringEscapeUtils.unescapeJava( this.lineSeparator ) );
3315             }
3316 
3317             if ( this.locale != null )
3318             {
3319                 tool.setLocale( new Locale( StringUtils.defaultString( this.locale.getLanguage() ),
3320                                             StringUtils.defaultString( this.locale.getCountry() ),
3321                                             StringUtils.defaultString( this.locale.getVariant() ) ) );
3322 
3323             }
3324 
3325             if ( this.velocityPropertyResources != null )
3326             {
3327                 for ( int i = 0, s0 = this.velocityPropertyResources.size(); i < s0; i++ )
3328                 {
3329                     for ( final Map.Entry<Object, Object> e : this.getProperties(
3330                         context, this.velocityPropertyResources.get( i ) ).entrySet() )
3331                     {
3332                         if ( e.getValue() != null )
3333                         {
3334                             tool.getVelocityEngine().setProperty( e.getKey().toString(), e );
3335                         }
3336                         else
3337                         {
3338                             tool.getVelocityEngine().clearProperty( e.getKey().toString() );
3339                         }
3340                     }
3341                 }
3342             }
3343 
3344             if ( this.velocityProperties != null )
3345             {
3346                 for ( final VelocityProperty e : this.velocityProperties )
3347                 {
3348                     final Object object = e.getObject( context );
3349 
3350                     if ( object != null )
3351                     {
3352                         tool.getVelocityEngine().setProperty( e.getKey(), object );
3353                     }
3354                     else
3355                     {
3356                         tool.getVelocityEngine().clearProperty( e.getKey() );
3357                     }
3358                 }
3359             }
3360 
3361             for ( final Map.Entry<Object, Object> e : System.getProperties().entrySet() )
3362             {
3363                 tool.getTemplateParameters().put( e.getKey().toString(), e.getValue() );
3364             }
3365 
3366             if ( this.getMavenProject().getProperties() != null )
3367             {
3368                 for ( final Map.Entry<Object, Object> e : System.getProperties().entrySet() )
3369                 {
3370                     tool.getTemplateParameters().put( e.getKey().toString(), e.getValue() );
3371                 }
3372             }
3373 
3374             if ( this.templateParameterResources != null )
3375             {
3376                 for ( int i = 0, s0 = this.templateParameterResources.size(); i < s0; i++ )
3377                 {
3378                     for ( final Map.Entry<Object, Object> e : this.getProperties(
3379                         context, this.templateParameterResources.get( i ) ).entrySet() )
3380                     {
3381                         if ( e.getValue() != null )
3382                         {
3383                             tool.getTemplateParameters().put( e.getKey().toString(), e.getValue() );
3384                         }
3385                         else
3386                         {
3387                             tool.getTemplateParameters().remove( e.getKey().toString() );
3388                         }
3389                     }
3390                 }
3391             }
3392 
3393             if ( this.templateParameters != null )
3394             {
3395                 for ( final TemplateParameter e : this.templateParameters )
3396                 {
3397                     final Object object = e.getObject( context );
3398 
3399                     if ( object != null )
3400                     {
3401                         tool.getTemplateParameters().put( e.getKey(), object );
3402                     }
3403                     else
3404                     {
3405                         tool.getTemplateParameters().remove( e.getKey() );
3406                     }
3407                 }
3408             }
3409 
3410             if ( this.templateLocation != null )
3411             {
3412                 final URL url = this.getDirectory( this.templateLocation );
3413                 tool.setTemplateLocation( url );
3414 
3415                 if ( url == null && this.isLoggable( Level.WARNING ) )
3416                 {
3417                     this.log( Level.WARNING, Messages.getMessage( "locationNotFound", this.templateLocation ), null );
3418                 }
3419             }
3420         }
3421         catch ( final InstantiationException e )
3422         {
3423             throw new MojoExecutionException( Messages.getMessage( e ), e );
3424         }
3425         catch ( final IOException e )
3426         {
3427             throw new MojoExecutionException( Messages.getMessage( e ), e );
3428         }
3429     }
3430 
3431     private Artifact getPluginArtifact( final Artifact a )
3432     {
3433         for ( int i = 0, s0 = this.pluginArtifacts.size(); i < s0; i++ )
3434         {
3435             final Artifact pluginArtifact = this.pluginArtifacts.get( i );
3436 
3437             if ( pluginArtifact.getGroupId().equals( a.getGroupId() )
3438                      && pluginArtifact.getArtifactId().equals( a.getArtifactId() )
3439                      && ( pluginArtifact.hasClassifier()
3440                           ? pluginArtifact.getClassifier().equals( a.getClassifier() )
3441                           : !a.hasClassifier() ) )
3442             {
3443                 return pluginArtifact;
3444             }
3445         }
3446 
3447         return null;
3448     }
3449 
3450 }