001/*
002 *   Copyright (C) Christian Schulte, 2005-206
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 4613 2012-09-22 10:07:08Z 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.jomc.model.Module;
044import org.jomc.modlet.ModelContext;
045import org.jomc.modlet.ModelValidationReport;
046import org.jomc.modlet.ObjectFactory;
047import org.jomc.tools.ClassFileProcessor;
048
049/**
050 * Base class for committing model objects to class files.
051 *
052 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
053 * @version $JOMC: AbstractClassesCommitMojo.java 4613 2012-09-22 10:07:08Z schulte $
054 */
055public abstract class AbstractClassesCommitMojo extends AbstractJomcMojo
056{
057
058    /** Constant for the name of the tool backing the mojo. */
059    private static final String TOOLNAME = "ClassFileProcessor";
060
061    /**
062     * XSLT document to use for transforming model objects.
063     * <p>The value of the parameter is a location to search a XSLT document at. First the value is used to search the
064     * class path of the plugin. If a class path resource is found, a XSLT document is loaded from that resource. If no
065     * class path resource is found, an attempt is made to parse the value to an URL. Succeeding that, an XSLT document
066     * is loaded from that URL (since version 1.2). Failing that, the value is interpreted as a file name of a XSLT
067     * document to load relative to the base directory of the project. If that file exists, a XSLT document is loaded
068     * from that file. If no XSLT document is found at the given location, a build failure is produced.</p>
069     * <p><b>Note:</b> When upgrading to version 1.2, any project dependencies holding XSLT documents referenced by this
070     * parameter need to be added to the plugins' dependencies.</p>
071     * <p><strong>Deprecated:</strong> As of JOMC 1.2, please use the 'modelObjectStylesheetResources' parameter. This
072     * parameter will be removed in version 2.0.</p>
073     *
074     * @parameter
075     */
076    @Deprecated
077    private String modelObjectStylesheet;
078
079    /**
080     * XSLT documents to use for transforming model objects.
081     * <pre>
082     * &lt;modelObjectStylesheetResources>
083     *   &lt;modelObjectStylesheetResource>
084     *     &lt;location>The location of the XSLT document.&lt;/location>
085     *     &lt;optional>Flag indicating the XSLT document is optional.&lt;/optional>
086     *     &lt;connectTimeout>Timeout value, in milliseconds.&lt;/connectTimeout>
087     *     &lt;readTimeout>Timeout value, in milliseconds.&lt;/readTimeout>
088     *     &lt;transformationParameterResources>
089     *       &lt;transformationParameterResource>
090     *         &lt;location>The location of the properties resource.&lt;/location>
091     *         &lt;optional>Flag indicating the properties resource is optional.&lt;/optional>
092     *         &lt;format>The format of the properties resource.&lt;/format>
093     *         &lt;connectTimeout>Timeout value, in milliseconds.&lt;/connectTimeout>
094     *         &lt;readTimeout>Timeout value, in milliseconds.&lt;/readTimeout>
095     *       &lt;/transformationParameterResource>
096     *     &lt;/transformationParameterResources>
097     *     &lt;transformationParameters>
098     *       &lt;transformationParameter>
099     *         &lt;key>The name of the parameter.&lt;/key>
100     *         &lt;value>The value of the parameter.&lt;/value>
101     *         &lt;type>The name of the class of the parameter's object.&lt;/type>
102     *       &lt;/transformationParameter>
103     *     &lt;/transformationParameters>
104     *     &lt;transformationOutputProperties>
105     *       &lt;transformationOutputProperty>
106     *         &lt;key>The name of the property.&lt;/key>
107     *         &lt;value>The value of the property.&lt;/value>
108     *         &lt;type>The name of the class of the properties object.&lt;/type>
109     *       &lt;/transformationOutputProperty>
110     *     &lt;/transformationOutputProperties>
111     *   &lt;/modelObjectStylesheetResource>
112     * &lt;/modelObjectStylesheetResources>
113     * </pre>
114     * <p>The location value is used to first search the class path of the plugin. If a class path resource is found,
115     * that resource is used. If no class path resource is found, an attempt is made to parse the location value to an
116     * URL. On successful parsing, that URL is used. Otherwise the location value is interpreted as a file name relative
117     * to the base directory of the project. If that file exists, that file is used. If nothing is found at the given
118     * location, depending on the optional flag, a warning message is logged or a build failure is produced.</p>
119     * <p>The optional flag is used to flag the resource optional. When an optional resource is not found, a warning
120     * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false</p>
121     * <p>The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening
122     * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/>
123     * <b>Default value is:</b> 60000</p>
124     * <p>The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource.
125     * A timeout of zero is interpreted as an infinite timeout.<br/>
126     * <b>Default value is:</b> 60000</p>
127     *
128     * @parameter
129     * @since 1.2
130     */
131    private List<ModelObjectStylesheetResource> modelObjectStylesheetResources;
132
133    /** Creates a new {@code AbstractClassesCommitMojo} instance. */
134    public AbstractClassesCommitMojo()
135    {
136        super();
137    }
138
139    /**
140     * Gets transformers to use for transforming model objects.
141     *
142     * @param classLoader The class loader to use for loading a transformer class path resource.
143     *
144     * @return A list of transformers to use for transforming model objects.
145     *
146     * @throws NullPointerException if {@code classLoader} is {@code null}.
147     * @throws MojoExecutionException if getting the transformers fails.
148     *
149     * @deprecated As of JOMC 1.2, the dependencies of the project are no longer searched for XSLT documents. Please
150     * use method {@link #getTransformers()}. This method will be removed in version 2.0.
151     */
152    @Deprecated
153    protected List<Transformer> getTransformers( final ClassLoader classLoader ) throws MojoExecutionException
154    {
155        if ( classLoader == null )
156        {
157            throw new NullPointerException( "classLoader" );
158        }
159
160        return this.getTransformers();
161    }
162
163    /**
164     * Gets transformers to use for transforming model objects.
165     *
166     * @return A list of transformers to use for transforming model objects.
167     *
168     * @throws MojoExecutionException if getting the transformers fails.
169     *
170     * @since 1.2
171     */
172    protected List<Transformer> getTransformers() throws MojoExecutionException
173    {
174        final List<Transformer> transformers = new ArrayList<Transformer>(
175            this.modelObjectStylesheetResources != null ? this.modelObjectStylesheetResources.size() + 1 : 1 );
176
177        if ( this.modelObjectStylesheet != null )
178        {
179            final TransformerResourceType r = new TransformerResourceType();
180            r.setLocation( this.modelObjectStylesheet );
181
182            final Transformer transformer = this.getTransformer( r );
183
184            if ( transformer != null )
185            {
186                transformers.add( transformer );
187            }
188        }
189
190        if ( this.modelObjectStylesheetResources != null )
191        {
192            for ( int i = 0, s0 = this.modelObjectStylesheetResources.size(); i < s0; i++ )
193            {
194                final Transformer transformer = this.getTransformer( this.modelObjectStylesheetResources.get( i ) );
195
196                if ( transformer != null )
197                {
198                    transformers.add( transformer );
199                }
200            }
201        }
202
203        return transformers;
204    }
205
206    @Override
207    protected void assertValidParameters() throws MojoFailureException
208    {
209        super.assertValidParameters();
210        this.assertValidResources( this.modelObjectStylesheetResources );
211    }
212
213    @Override
214    protected final void executeTool() throws Exception
215    {
216        this.logSeparator();
217
218        if ( this.isClassProcessingEnabled() )
219        {
220            this.logProcessingModule( TOOLNAME, this.getClassesModuleName() );
221
222            final ClassLoader classLoader = this.getClassesClassLoader();
223            final ModelContext context = this.createModelContext( classLoader );
224            final ClassFileProcessor tool = this.createClassFileProcessor( context );
225            final JAXBContext jaxbContext = context.createContext( this.getModel() );
226            final List<Transformer> transformers = this.getTransformers();
227            final Source source = new JAXBSource( jaxbContext, new ObjectFactory().createModel( tool.getModel() ) );
228            final ModelValidationReport validationReport = context.validateModel( this.getModel(), source );
229
230            this.log( context, validationReport.isModelValid() ? Level.INFO : Level.SEVERE, validationReport );
231
232            if ( validationReport.isModelValid() )
233            {
234                final Module module =
235                    tool.getModules() != null ? tool.getModules().getModule( this.getClassesModuleName() ) : null;
236
237                if ( module != null )
238                {
239                    tool.commitModelObjects( module, context, this.getClassesDirectory() );
240
241                    if ( !transformers.isEmpty() )
242                    {
243                        tool.transformModelObjects( module, context, this.getClassesDirectory(), transformers );
244                    }
245
246                    this.logToolSuccess( TOOLNAME );
247                }
248                else
249                {
250                    this.logMissingModule( this.getClassesModuleName() );
251                }
252            }
253            else
254            {
255                throw new MojoExecutionException( Messages.getMessage( "classFileProcessingFailure" ) );
256            }
257        }
258        else if ( this.isLoggable( Level.INFO ) )
259        {
260            this.log( Level.INFO, Messages.getMessage( "classFileProcessingDisabled" ), null );
261        }
262    }
263
264    /**
265     * Gets the name of the module to commit class file model objects of.
266     *
267     * @return The name of the module to commit class file model objects of.
268     *
269     * @throws MojoExecutionException if getting the name fails.
270     */
271    protected abstract String getClassesModuleName() throws MojoExecutionException;
272
273    /**
274     * Gets the class loader to use for committing class file model objects.
275     *
276     * @return The class loader to use for committing class file model objects.
277     *
278     * @throws MojoExecutionException if getting the class loader fails.
279     */
280    protected abstract ClassLoader getClassesClassLoader() throws MojoExecutionException;
281
282    /**
283     * Gets the directory holding the class files to commit model objects to.
284     *
285     * @return The directory holding the class files to commit model objects to.
286     *
287     * @throws MojoExecutionException if getting the directory fails.
288     */
289    protected abstract File getClassesDirectory() throws MojoExecutionException;
290
291}