001/*
002 *   Copyright (C) 2005 Christian Schulte <cs@schulte.it>
003 *   All rights reserved.
004 *
005 *   Redistribution and use in source and binary forms, with or without
006 *   modification, are permitted provided that the following conditions
007 *   are met:
008 *
009 *     o Redistributions of source code must retain the above copyright
010 *       notice, this list of conditions and the following disclaimer.
011 *
012 *     o Redistributions in binary form must reproduce the above copyright
013 *       notice, this list of conditions and the following disclaimer in
014 *       the documentation and/or other materials provided with the
015 *       distribution.
016 *
017 *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
018 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
019 *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
020 *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
021 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027 *
028 *   $JOMC: AbstractClassesCommitMojo.java 5228 2016-04-24 11:08:06Z schulte $
029 *
030 */
031package org.jomc.mojo;
032
033import java.io.File;
034import java.util.ArrayList;
035import java.util.List;
036import java.util.logging.Level;
037import javax.xml.bind.JAXBContext;
038import javax.xml.bind.util.JAXBSource;
039import javax.xml.transform.Source;
040import javax.xml.transform.Transformer;
041import org.apache.maven.plugin.MojoExecutionException;
042import org.apache.maven.plugin.MojoFailureException;
043import org.apache.maven.plugins.annotations.Parameter;
044import org.jomc.model.Module;
045import org.jomc.modlet.ModelContext;
046import org.jomc.modlet.ModelValidationReport;
047import org.jomc.modlet.ObjectFactory;
048import org.jomc.tools.ClassFileProcessor;
049
050/**
051 * Base class for committing model objects to class files.
052 *
053 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
054 * @version $JOMC: AbstractClassesCommitMojo.java 5228 2016-04-24 11:08:06Z schulte $
055 */
056public abstract class AbstractClassesCommitMojo extends AbstractJomcMojo
057{
058
059    /**
060     * Constant for the name of the tool backing the mojo.
061     */
062    private static final String TOOLNAME = "ClassFileProcessor";
063
064    /**
065     * XSLT document to use for transforming model objects.
066     * <p>
067     * The value of the parameter is a location to search a XSLT document at. First the value is used to search the
068     * class path of the plugin. If a class path resource is found, a XSLT document is loaded from that resource. If no
069     * class path resource is found, an attempt is made to parse the value to an URL. Succeeding that, an XSLT document
070     * is loaded from that URL (since version 1.2). Failing that, the value is interpreted as a file name of a XSLT
071     * document to load relative to the base directory of the project. If that file exists, a XSLT document is loaded
072     * from that file. If no XSLT document is found at the given location, a build failure is produced.</p>
073     * <p>
074     * <b>Note:</b> When upgrading to version 1.2, any project dependencies holding XSLT documents referenced by this
075     * parameter need to be added to the plugins' dependencies.</p>
076     * <p>
077     * <strong>Deprecated:</strong> As of JOMC 1.2, please use the 'modelObjectStylesheetResources' parameter. This
078     * parameter will be removed in version 2.0.</p>
079     */
080    @Deprecated
081    @Parameter( name = "modelObjectStylesheet" )
082    private String modelObjectStylesheet;
083
084    /**
085     * XSLT documents to use for transforming model objects.
086     * <pre>
087     * &lt;modelObjectStylesheetResources>
088     *   &lt;modelObjectStylesheetResource>
089     *     &lt;location>The location of the XSLT document.&lt;/location>
090     *     &lt;optional>Flag indicating the XSLT document is optional.&lt;/optional>
091     *     &lt;connectTimeout>Timeout value, in milliseconds.&lt;/connectTimeout>
092     *     &lt;readTimeout>Timeout value, in milliseconds.&lt;/readTimeout>
093     *     &lt;transformationParameterResources>
094     *       &lt;transformationParameterResource>
095     *         &lt;location>The location of the properties resource.&lt;/location>
096     *         &lt;optional>Flag indicating the properties resource is optional.&lt;/optional>
097     *         &lt;format>The format of the properties resource.&lt;/format>
098     *         &lt;connectTimeout>Timeout value, in milliseconds.&lt;/connectTimeout>
099     *         &lt;readTimeout>Timeout value, in milliseconds.&lt;/readTimeout>
100     *       &lt;/transformationParameterResource>
101     *     &lt;/transformationParameterResources>
102     *     &lt;transformationParameters>
103     *       &lt;transformationParameter>
104     *         &lt;key>The name of the parameter.&lt;/key>
105     *         &lt;value>The value of the parameter.&lt;/value>
106     *         &lt;type>The name of the class of the parameter's object.&lt;/type>
107     *       &lt;/transformationParameter>
108     *     &lt;/transformationParameters>
109     *     &lt;transformationOutputProperties>
110     *       &lt;transformationOutputProperty>
111     *         &lt;key>The name of the property.&lt;/key>
112     *         &lt;value>The value of the property.&lt;/value>
113     *         &lt;type>The name of the class of the properties object.&lt;/type>
114     *       &lt;/transformationOutputProperty>
115     *     &lt;/transformationOutputProperties>
116     *   &lt;/modelObjectStylesheetResource>
117     * &lt;/modelObjectStylesheetResources>
118     * </pre>
119     * <p>
120     * The location value is used to first search the class path of the plugin and the project's main or test class
121     * path. If a class path resource is found, that resource is used. If no class path resource is found, an attempt is
122     * made to parse the location value to an URL. On successful parsing, that URL is used. Otherwise the location value
123     * is interpreted as a file name relative to the base directory of the project. If that file exists, that file is
124     * used. If nothing is found at the given location, depending on the optional flag, a warning message is logged or a
125     * build failure is produced.
126     * </p>
127     * <p>
128     * The optional flag is used to flag the resource optional. When an optional resource is not found, a warning
129     * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false
130     * </p>
131     * <p>
132     * The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening
133     * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/>
134     * <b>Default value is:</b> 60000
135     * </p>
136     * <p>
137     * The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource.
138     * A timeout of zero is interpreted as an infinite timeout.<br/>
139     * <b>Default value is:</b> 60000
140     * </p>
141     *
142     * @since 1.2
143     */
144    @Parameter( name = "modelObjectStylesheetResources" )
145    private List<ModelObjectStylesheetResource> modelObjectStylesheetResources;
146
147    /**
148     * Creates a new {@code AbstractClassesCommitMojo} instance.
149     */
150    public AbstractClassesCommitMojo()
151    {
152        super();
153    }
154
155    /**
156     * Gets transformers to use for transforming model objects.
157     *
158     * @param classLoader The class loader to use for loading a transformer class path resource.
159     *
160     * @return A list of transformers to use for transforming model objects.
161     *
162     * @throws NullPointerException if {@code classLoader} is {@code null}.
163     * @throws MojoExecutionException if getting the transformers fails.
164     *
165     * @deprecated As of JOMC 1.2, the dependencies of the project are no longer searched for XSLT documents. Please
166     * use method {@link #getTransformers()}. This method will be removed in version 2.0.
167     */
168    @Deprecated
169    protected List<Transformer> getTransformers( final ClassLoader classLoader ) throws MojoExecutionException
170    {
171        if ( classLoader == null )
172        {
173            throw new NullPointerException( "classLoader" );
174        }
175
176        return this.getTransformers();
177    }
178
179    /**
180     * Gets transformers to use for transforming model objects.
181     *
182     * @return A list of transformers to use for transforming model objects.
183     *
184     * @throws MojoExecutionException if getting the transformers fails.
185     *
186     * @since 1.2
187     * @deprecated As of JOMC 1.8, replaced by method {@link #getTransformers(org.jomc.modlet.ModelContext)}. This
188     * method will be removed in JOMC 2.0.
189     */
190    @Deprecated
191    @SuppressWarnings( "deprecation" )
192    protected List<Transformer> getTransformers() throws MojoExecutionException
193    {
194        final List<Transformer> transformers = new ArrayList<Transformer>(
195            this.modelObjectStylesheetResources != null ? this.modelObjectStylesheetResources.size() + 1 : 1 );
196
197        if ( this.modelObjectStylesheet != null )
198        {
199            final TransformerResourceType r = new TransformerResourceType();
200            r.setLocation( this.modelObjectStylesheet );
201
202            final Transformer transformer = this.getTransformer( r );
203
204            if ( transformer != null )
205            {
206                transformers.add( transformer );
207            }
208        }
209
210        if ( this.modelObjectStylesheetResources != null )
211        {
212            for ( int i = 0, s0 = this.modelObjectStylesheetResources.size(); i < s0; i++ )
213            {
214                final Transformer transformer = this.getTransformer( this.modelObjectStylesheetResources.get( i ) );
215
216                if ( transformer != null )
217                {
218                    transformers.add( transformer );
219                }
220            }
221        }
222
223        return transformers;
224    }
225
226    /**
227     * Gets transformers to use for transforming model objects.
228     *
229     * @param modelContext The model context to search.
230     *
231     * @return A list of transformers to use for transforming model objects.
232     *
233     * @throws NullPointerException if {@code modelContext} is {@code null}.
234     * @throws MojoExecutionException if getting the transformers fails.
235     *
236     * @since 1.8
237     */
238    protected List<Transformer> getTransformers( final ModelContext modelContext ) throws MojoExecutionException
239    {
240        if ( modelContext == null )
241        {
242            throw new NullPointerException( "modelContext" );
243        }
244
245        final List<Transformer> transformers = new ArrayList<Transformer>(
246            this.modelObjectStylesheetResources != null ? this.modelObjectStylesheetResources.size() : 0 );
247
248        if ( this.modelObjectStylesheetResources != null )
249        {
250            for ( int i = 0, s0 = this.modelObjectStylesheetResources.size(); i < s0; i++ )
251            {
252                final Transformer transformer =
253                    this.getTransformer( modelContext, this.modelObjectStylesheetResources.get( i ) );
254
255                if ( transformer != null )
256                {
257                    transformers.add( transformer );
258                }
259            }
260        }
261
262        return transformers;
263    }
264
265    @Override
266    protected void assertValidParameters() throws MojoFailureException
267    {
268        super.assertValidParameters();
269        this.assertValidResources( this.modelObjectStylesheetResources );
270    }
271
272    @Override
273    protected final void executeTool() throws Exception
274    {
275        this.logSeparator();
276
277        if ( this.isClassProcessingEnabled() )
278        {
279            this.logProcessingModule( TOOLNAME, this.getClassesModuleName() );
280
281            final ClassLoader classLoader = this.getClassesClassLoader();
282            final ModelContext context = this.createModelContext( classLoader );
283            final ClassFileProcessor tool = this.createClassFileProcessor( context );
284            final JAXBContext jaxbContext = context.createContext( this.getModel() );
285            final List<Transformer> transformers = this.getTransformers( context );
286            final Source source = new JAXBSource( jaxbContext, new ObjectFactory().createModel( tool.getModel() ) );
287            final ModelValidationReport validationReport = context.validateModel( this.getModel(), source );
288
289            this.log( context, validationReport.isModelValid() ? Level.INFO : Level.SEVERE, validationReport );
290
291            if ( validationReport.isModelValid() )
292            {
293                final Module module =
294                    tool.getModules() != null ? tool.getModules().getModule( this.getClassesModuleName() ) : null;
295
296                if ( module != null )
297                {
298                    tool.commitModelObjects( module, context, this.getClassesDirectory() );
299
300                    if ( !transformers.isEmpty() )
301                    {
302                        tool.transformModelObjects( module, context, this.getClassesDirectory(), transformers );
303                    }
304
305                    this.logToolSuccess( TOOLNAME );
306                }
307                else
308                {
309                    this.logMissingModule( this.getClassesModuleName() );
310                }
311            }
312            else
313            {
314                throw new MojoExecutionException( Messages.getMessage( "classFileProcessingFailure" ) );
315            }
316        }
317        else if ( this.isLoggable( Level.INFO ) )
318        {
319            this.log( Level.INFO, Messages.getMessage( "classFileProcessingDisabled" ), null );
320        }
321    }
322
323    /**
324     * Gets the name of the module to commit class file model objects of.
325     *
326     * @return The name of the module to commit class file model objects of.
327     *
328     * @throws MojoExecutionException if getting the name fails.
329     */
330    protected abstract String getClassesModuleName() throws MojoExecutionException;
331
332    /**
333     * Gets the class loader to use for committing class file model objects.
334     *
335     * @return The class loader to use for committing class file model objects.
336     *
337     * @throws MojoExecutionException if getting the class loader fails.
338     */
339    protected abstract ClassLoader getClassesClassLoader() throws MojoExecutionException;
340
341    /**
342     * Gets the directory holding the class files to commit model objects to.
343     *
344     * @return The directory holding the class files to commit model objects to.
345     *
346     * @throws MojoExecutionException if getting the directory fails.
347     */
348    protected abstract File getClassesDirectory() throws MojoExecutionException;
349
350}