View Javadoc
1   /*
2    *   Copyright (C) Christian Schulte <cs@schulte.it>, 2005-206
3    *   All rights reserved.
4    *
5    *   Redistribution and use in source and binary forms, with or without
6    *   modification, are permitted provided that the following conditions
7    *   are met:
8    *
9    *     o Redistributions of source code must retain the above copyright
10   *       notice, this list of conditions and the following disclaimer.
11   *
12   *     o Redistributions in binary form must reproduce the above copyright
13   *       notice, this list of conditions and the following disclaimer in
14   *       the documentation and/or other materials provided with the
15   *       distribution.
16   *
17   *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18   *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19   *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20   *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
21   *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22   *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23   *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24   *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25   *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26   *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27   *
28   *   $JOMC: CommitClassesTask.java 5043 2015-05-27 07:03:39Z schulte $
29   *
30   */
31  package org.jomc.ant;
32  
33  import java.io.File;
34  import java.io.IOException;
35  import java.util.ArrayList;
36  import java.util.LinkedList;
37  import java.util.List;
38  import java.util.logging.Level;
39  import javax.xml.bind.JAXBContext;
40  import javax.xml.bind.JAXBException;
41  import javax.xml.bind.util.JAXBSource;
42  import javax.xml.transform.Source;
43  import javax.xml.transform.Transformer;
44  import javax.xml.transform.TransformerConfigurationException;
45  import org.apache.tools.ant.BuildException;
46  import org.jomc.ant.types.TransformerResourceType;
47  import org.jomc.model.Implementation;
48  import org.jomc.model.Module;
49  import org.jomc.model.Specification;
50  import org.jomc.modlet.Model;
51  import org.jomc.modlet.ModelContext;
52  import org.jomc.modlet.ModelException;
53  import org.jomc.modlet.ModelValidationReport;
54  import org.jomc.modlet.ObjectFactory;
55  import org.jomc.tools.ClassFileProcessor;
56  
57  /**
58   * Task for committing model objects to class files.
59   *
60   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
61   * @version $JOMC: CommitClassesTask.java 5043 2015-05-27 07:03:39Z schulte $
62   */
63  public final class CommitClassesTask extends ClassFileProcessorTask
64  {
65  
66      /**
67       * The directory holding the class files to commit model objects to.
68       */
69      private File classesDirectory;
70  
71      /**
72       * XSLT documents to use for transforming model objects.
73       */
74      private List<TransformerResourceType> modelObjectStylesheetResources;
75  
76      /**
77       * Creates a new {@code CommitClassesTask} instance.
78       */
79      public CommitClassesTask()
80      {
81          super();
82      }
83  
84      /**
85       * Gets the directory holding the class files to commit model objects to.
86       *
87       * @return The directory holding the class files to commit model objects to or {@code null}.
88       *
89       * @see #setClassesDirectory(java.io.File)
90       */
91      public File getClassesDirectory()
92      {
93          return this.classesDirectory;
94      }
95  
96      /**
97       * Sets the directory holding the class files to commit model objects to.
98       *
99       * @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 }