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 4174 2012-01-15 09:30:01Z schulte2005 $
029     *
030     */
031    package org.jomc.ant;
032    
033    import java.io.File;
034    import java.io.IOException;
035    import java.util.ArrayList;
036    import java.util.LinkedList;
037    import java.util.List;
038    import java.util.logging.Level;
039    import javax.xml.bind.JAXBContext;
040    import javax.xml.bind.JAXBException;
041    import javax.xml.bind.util.JAXBSource;
042    import javax.xml.transform.Source;
043    import javax.xml.transform.Transformer;
044    import javax.xml.transform.TransformerConfigurationException;
045    import org.apache.tools.ant.BuildException;
046    import org.jomc.ant.types.TransformerResourceType;
047    import org.jomc.model.Implementation;
048    import org.jomc.model.Module;
049    import org.jomc.model.Specification;
050    import org.jomc.modlet.Model;
051    import org.jomc.modlet.ModelContext;
052    import org.jomc.modlet.ModelException;
053    import org.jomc.modlet.ModelValidationReport;
054    import org.jomc.modlet.ObjectFactory;
055    import org.jomc.tools.ClassFileProcessor;
056    
057    /**
058     * Task for committing model objects to class files.
059     *
060     * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
061     * @version $JOMC: CommitClassesTask.java 4174 2012-01-15 09:30:01Z schulte2005 $
062     */
063    public 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    }