View Javadoc

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