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