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 3880 2011-10-24 01:00:25Z schulte2005 $
029     *
030     */
031    package org.jomc.mojo;
032    
033    import java.io.File;
034    import java.util.ArrayList;
035    import java.util.List;
036    import java.util.logging.Level;
037    import javax.xml.bind.JAXBContext;
038    import javax.xml.bind.util.JAXBSource;
039    import javax.xml.transform.Source;
040    import javax.xml.transform.Transformer;
041    import org.apache.maven.plugin.MojoExecutionException;
042    import org.apache.maven.plugin.MojoFailureException;
043    import org.jomc.model.Module;
044    import org.jomc.modlet.ModelContext;
045    import org.jomc.modlet.ModelValidationReport;
046    import org.jomc.modlet.ObjectFactory;
047    import org.jomc.tools.ClassFileProcessor;
048    
049    /**
050     * Base class for committing model objects to class files.
051     *
052     * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
053     * @version $JOMC: AbstractClassesCommitMojo.java 3880 2011-10-24 01:00:25Z schulte2005 $
054     */
055    public 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 = tool.getModules().getModule( this.getClassesModuleName() );
235    
236                    if ( module != null )
237                    {
238                        tool.commitModelObjects( module, context, this.getClassesDirectory() );
239    
240                        if ( !transformers.isEmpty() )
241                        {
242                            tool.transformModelObjects( module, context, this.getClassesDirectory(), transformers );
243                        }
244    
245                        this.logToolSuccess( TOOLNAME );
246                    }
247                    else
248                    {
249                        this.logMissingModule( this.getClassesModuleName() );
250                    }
251                }
252                else
253                {
254                    throw new MojoExecutionException( Messages.getMessage( "classFileProcessingFailure" ) );
255                }
256            }
257            else if ( this.isLoggable( Level.INFO ) )
258            {
259                this.log( Level.INFO, Messages.getMessage( "classFileProcessingDisabled" ), null );
260            }
261        }
262    
263        /**
264         * Gets the name of the module to commit class file model objects of.
265         *
266         * @return The name of the module to commit class file model objects of.
267         *
268         * @throws MojoExecutionException if getting the name fails.
269         */
270        protected abstract String getClassesModuleName() throws MojoExecutionException;
271    
272        /**
273         * Gets the class loader to use for committing class file model objects.
274         *
275         * @return The class loader to use for committing class file model objects.
276         *
277         * @throws MojoExecutionException if getting the class loader fails.
278         */
279        protected abstract ClassLoader getClassesClassLoader() throws MojoExecutionException;
280    
281        /**
282         * Gets the directory holding the class files to commit model objects to.
283         *
284         * @return The directory holding the class files to commit model objects to.
285         *
286         * @throws MojoExecutionException if getting the directory fails.
287         */
288        protected abstract File getClassesDirectory() throws MojoExecutionException;
289    
290    }