001/*
002 *   Copyright (C) Christian Schulte <cs@schulte.it>, 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: CommitClassesTask.java 5043 2015-05-27 07:03:39Z schulte $
029 *
030 */
031package org.jomc.ant;
032
033import java.io.File;
034import java.io.IOException;
035import java.util.ArrayList;
036import java.util.LinkedList;
037import java.util.List;
038import java.util.logging.Level;
039import javax.xml.bind.JAXBContext;
040import javax.xml.bind.JAXBException;
041import javax.xml.bind.util.JAXBSource;
042import javax.xml.transform.Source;
043import javax.xml.transform.Transformer;
044import javax.xml.transform.TransformerConfigurationException;
045import org.apache.tools.ant.BuildException;
046import org.jomc.ant.types.TransformerResourceType;
047import org.jomc.model.Implementation;
048import org.jomc.model.Module;
049import org.jomc.model.Specification;
050import org.jomc.modlet.Model;
051import org.jomc.modlet.ModelContext;
052import org.jomc.modlet.ModelException;
053import org.jomc.modlet.ModelValidationReport;
054import org.jomc.modlet.ObjectFactory;
055import org.jomc.tools.ClassFileProcessor;
056
057/**
058 * Task for committing model objects to class files.
059 *
060 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
061 * @version $JOMC: CommitClassesTask.java 5043 2015-05-27 07:03:39Z schulte $
062 */
063public final class CommitClassesTask extends ClassFileProcessorTask
064{
065
066    /**
067     * The directory holding the class files to commit model objects to.
068     */
069    private File classesDirectory;
070
071    /**
072     * XSLT documents to use for transforming model objects.
073     */
074    private List<TransformerResourceType> modelObjectStylesheetResources;
075
076    /**
077     * Creates a new {@code CommitClassesTask} instance.
078     */
079    public CommitClassesTask()
080    {
081        super();
082    }
083
084    /**
085     * Gets the directory holding the class files to commit model objects to.
086     *
087     * @return The directory holding the class files to commit model objects to or {@code null}.
088     *
089     * @see #setClassesDirectory(java.io.File)
090     */
091    public File getClassesDirectory()
092    {
093        return this.classesDirectory;
094    }
095
096    /**
097     * Sets the directory holding the class files to commit model objects to.
098     *
099     * @param value The new directory holding the class files to commit model objects to or {@code null}.
100     *
101     * @see #getClassesDirectory()
102     */
103    public void setClassesDirectory( final File value )
104    {
105        this.classesDirectory = value;
106    }
107
108    /**
109     * Gets the XSLT documents to use for transforming model objects.
110     * <p>
111     * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
112     * to the returned list will be present inside the object. This is why there is no {@code set} method for the
113     * model object stylesheet resources property.
114     * </p>
115     *
116     * @return The XSLT documents to use for transforming model objects.
117     *
118     * @see #createModelObjectStylesheetResource()
119     */
120    public List<TransformerResourceType> getModelObjectStylesheetResources()
121    {
122        if ( this.modelObjectStylesheetResources == null )
123        {
124            this.modelObjectStylesheetResources = new LinkedList<TransformerResourceType>();
125        }
126
127        return this.modelObjectStylesheetResources;
128    }
129
130    /**
131     * Creates a new {@code modelObjectStylesheetResource} element instance.
132     *
133     * @return A new {@code modelObjectStylesheetResource} element instance.
134     *
135     * @see #getModelObjectStylesheetResources()
136     */
137    public TransformerResourceType createModelObjectStylesheetResource()
138    {
139        final TransformerResourceType modelObjectStylesheetResource = new TransformerResourceType();
140        this.getModelObjectStylesheetResources().add( modelObjectStylesheetResource );
141        return modelObjectStylesheetResource;
142    }
143
144    /**
145     * {@inheritDoc}
146     */
147    @Override
148    public void preExecuteTask() throws BuildException
149    {
150        super.preExecuteTask();
151
152        this.assertNotNull( "classesDirectory", this.getClassesDirectory() );
153        this.assertLocationsNotNull( this.getModelObjectStylesheetResources() );
154    }
155
156    /**
157     * Commits model objects to class files.
158     *
159     * @throws BuildException if committing model objects fails.
160     */
161    @Override
162    public void processClassFiles() throws BuildException
163    {
164        ProjectClassLoader classLoader = null;
165        boolean suppressExceptionOnClose = true;
166
167        try
168        {
169            this.log( Messages.getMessage( "committingModelObjects", this.getModel() ) );
170
171            classLoader = this.newProjectClassLoader();
172            final ModelContext context = this.newModelContext( classLoader );
173            final ClassFileProcessor tool = this.newClassFileProcessor();
174            final JAXBContext jaxbContext = context.createContext( this.getModel() );
175            final Model model = this.getModel( context );
176            final Source source = new JAXBSource( jaxbContext, new ObjectFactory().createModel( model ) );
177            final ModelValidationReport validationReport = context.validateModel( this.getModel(), source );
178
179            this.logValidationReport( context, validationReport );
180            tool.setModel( model );
181
182            final List<Transformer> transformers =
183                new ArrayList<Transformer>( this.getModelObjectStylesheetResources().size() );
184
185            for ( int i = 0, s0 = this.getModelObjectStylesheetResources().size(); i < s0; i++ )
186            {
187                final Transformer transformer =
188                    this.getTransformer( this.getModelObjectStylesheetResources().get( i ) );
189
190                if ( transformer != null )
191                {
192                    transformers.add( transformer );
193                }
194            }
195
196            if ( validationReport.isModelValid() )
197            {
198                final Specification s = this.getSpecification( model );
199                final Implementation i = this.getImplementation( model );
200                final Module m = this.getModule( model );
201
202                if ( s != null )
203                {
204                    tool.commitModelObjects( s, context, this.getClassesDirectory() );
205
206                    if ( !transformers.isEmpty() )
207                    {
208                        tool.transformModelObjects( s, context, this.getClassesDirectory(), transformers );
209                    }
210                }
211
212                if ( i != null )
213                {
214                    tool.commitModelObjects( i, context, this.getClassesDirectory() );
215
216                    if ( !transformers.isEmpty() )
217                    {
218                        tool.transformModelObjects( i, context, this.getClassesDirectory(), transformers );
219                    }
220                }
221
222                if ( m != null )
223                {
224                    tool.commitModelObjects( m, context, this.getClassesDirectory() );
225
226                    if ( !transformers.isEmpty() )
227                    {
228                        tool.transformModelObjects( m, context, this.getClassesDirectory(), transformers );
229                    }
230                }
231
232                if ( this.isModulesProcessingRequested() )
233                {
234                    tool.commitModelObjects( context, this.getClassesDirectory() );
235
236                    if ( !transformers.isEmpty() )
237                    {
238                        tool.transformModelObjects( context, this.getClassesDirectory(), transformers );
239                    }
240                }
241
242                suppressExceptionOnClose = false;
243            }
244            else
245            {
246                throw new ModelException( Messages.getMessage( "invalidModel", this.getModel() ) );
247            }
248        }
249        catch ( final IOException e )
250        {
251            throw new ClassProcessingException( Messages.getMessage( e ), e, this.getLocation() );
252        }
253        catch ( final JAXBException e )
254        {
255            throw new ClassProcessingException( Messages.getMessage( e ), e, this.getLocation() );
256        }
257        catch ( final TransformerConfigurationException e )
258        {
259            throw new ClassProcessingException( Messages.getMessage( e ), e, this.getLocation() );
260        }
261        catch ( final ModelException e )
262        {
263            throw new ClassProcessingException( Messages.getMessage( e ), e, this.getLocation() );
264        }
265        finally
266        {
267            try
268            {
269                if ( classLoader != null )
270                {
271                    classLoader.close();
272                }
273            }
274            catch ( final IOException e )
275            {
276                if ( suppressExceptionOnClose )
277                {
278                    this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
279                }
280                else
281                {
282                    throw new ClassProcessingException( Messages.getMessage( e ), e, this.getLocation() );
283                }
284            }
285        }
286    }
287
288    /**
289     * {@inheritDoc}
290     */
291    @Override
292    public CommitClassesTask clone()
293    {
294        final CommitClassesTask clone = (CommitClassesTask) super.clone();
295        clone.classesDirectory =
296            this.classesDirectory != null ? new File( this.classesDirectory.getAbsolutePath() ) : null;
297
298        if ( this.modelObjectStylesheetResources != null )
299        {
300            clone.modelObjectStylesheetResources =
301                new ArrayList<TransformerResourceType>( this.modelObjectStylesheetResources.size() );
302
303            for ( final TransformerResourceType e : this.modelObjectStylesheetResources )
304            {
305                clone.modelObjectStylesheetResources.add( e.clone() );
306            }
307        }
308
309        return clone;
310    }
311
312}