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: CommitClassesTask.java 5179 2016-04-15 02:58:23Z 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 5179 2016-04-15 02:58:23Z 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
166        try
167        {
168            this.log( Messages.getMessage( "committingModelObjects", this.getModel() ) );
169
170            classLoader = this.newProjectClassLoader();
171            final ModelContext context = this.newModelContext( classLoader );
172            final ClassFileProcessor tool = this.newClassFileProcessor();
173            final JAXBContext jaxbContext = context.createContext( this.getModel() );
174            final Model model = this.getModel( context );
175            final Source source = new JAXBSource( jaxbContext, new ObjectFactory().createModel( model ) );
176            final ModelValidationReport validationReport = context.validateModel( this.getModel(), source );
177
178            this.logValidationReport( context, validationReport );
179            tool.setModel( model );
180
181            final List<Transformer> transformers =
182                new ArrayList<Transformer>( this.getModelObjectStylesheetResources().size() );
183
184            for ( int i = 0, s0 = this.getModelObjectStylesheetResources().size(); i < s0; i++ )
185            {
186                final Transformer transformer =
187                    this.getTransformer( this.getModelObjectStylesheetResources().get( i ) );
188
189                if ( transformer != null )
190                {
191                    transformers.add( transformer );
192                }
193            }
194
195            if ( validationReport.isModelValid() )
196            {
197                final Specification s = this.getSpecification( model );
198                final Implementation i = this.getImplementation( model );
199                final Module m = this.getModule( model );
200
201                if ( s != null )
202                {
203                    tool.commitModelObjects( s, context, this.getClassesDirectory() );
204
205                    if ( !transformers.isEmpty() )
206                    {
207                        tool.transformModelObjects( s, context, this.getClassesDirectory(), transformers );
208                    }
209                }
210
211                if ( i != null )
212                {
213                    tool.commitModelObjects( i, context, this.getClassesDirectory() );
214
215                    if ( !transformers.isEmpty() )
216                    {
217                        tool.transformModelObjects( i, context, this.getClassesDirectory(), transformers );
218                    }
219                }
220
221                if ( m != null )
222                {
223                    tool.commitModelObjects( m, context, this.getClassesDirectory() );
224
225                    if ( !transformers.isEmpty() )
226                    {
227                        tool.transformModelObjects( m, context, this.getClassesDirectory(), transformers );
228                    }
229                }
230
231                if ( this.isModulesProcessingRequested() )
232                {
233                    tool.commitModelObjects( context, this.getClassesDirectory() );
234
235                    if ( !transformers.isEmpty() )
236                    {
237                        tool.transformModelObjects( context, this.getClassesDirectory(), transformers );
238                    }
239                }
240
241                classLoader.close();
242                classLoader = null;
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                this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
277            }
278        }
279    }
280
281    /**
282     * {@inheritDoc}
283     */
284    @Override
285    public CommitClassesTask clone()
286    {
287        final CommitClassesTask clone = (CommitClassesTask) super.clone();
288        clone.classesDirectory =
289            this.classesDirectory != null ? new File( this.classesDirectory.getAbsolutePath() ) : null;
290
291        if ( this.modelObjectStylesheetResources != null )
292        {
293            clone.modelObjectStylesheetResources =
294                new ArrayList<TransformerResourceType>( this.modelObjectStylesheetResources.size() );
295
296            for ( final TransformerResourceType e : this.modelObjectStylesheetResources )
297            {
298                clone.modelObjectStylesheetResources.add( e.clone() );
299            }
300        }
301
302        return clone;
303    }
304
305}