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: WriteModelTask.java 4174 2012-01-15 09:30:01Z schulte2005 $
029     *
030     */
031    package org.jomc.ant;
032    
033    import java.io.BufferedReader;
034    import java.io.ByteArrayOutputStream;
035    import java.io.File;
036    import java.io.IOException;
037    import java.io.OutputStreamWriter;
038    import java.io.StringReader;
039    import java.io.StringWriter;
040    import java.util.logging.Level;
041    import javax.xml.bind.JAXBException;
042    import javax.xml.bind.Marshaller;
043    import javax.xml.bind.util.JAXBSource;
044    import org.apache.tools.ant.BuildException;
045    import org.apache.tools.ant.Project;
046    import org.jomc.model.Instance;
047    import org.jomc.model.Module;
048    import org.jomc.model.Modules;
049    import org.jomc.model.Specification;
050    import org.jomc.model.modlet.ModelHelper;
051    import org.jomc.modlet.Model;
052    import org.jomc.modlet.ModelContext;
053    import org.jomc.modlet.ModelException;
054    import org.jomc.modlet.ModelValidationReport;
055    import org.jomc.modlet.ObjectFactory;
056    
057    /**
058     * Task for writing model objects.
059     *
060     * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
061     * @version $JOMC: WriteModelTask.java 4174 2012-01-15 09:30:01Z schulte2005 $
062     */
063    public final class WriteModelTask extends JomcModelTask
064    {
065    
066        /** The identifier of a specification to write. */
067        private String specification;
068    
069        /** The identifier of an implementation to write. */
070        private String implementation;
071    
072        /** The name of a module to write. */
073        private String module;
074    
075        /** The encoding to use when writing the model. */
076        private String modelEncoding;
077    
078        /** File to write the model to. */
079        private File modelFile;
080    
081        /** Creates a new {@code WriteModelTask} instance. */
082        public WriteModelTask()
083        {
084            super();
085        }
086    
087        /**
088         * Gets the encoding of the model resource.
089         *
090         * @return The encoding of the model resource.
091         *
092         * @see #setModelEncoding(java.lang.String)
093         */
094        public String getModelEncoding()
095        {
096            if ( this.modelEncoding == null )
097            {
098                this.modelEncoding = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
099            }
100    
101            return this.modelEncoding;
102        }
103    
104        /**
105         * Sets the encoding of the model resource.
106         *
107         * @param value The new encoding of the model resource or {@code null}.
108         *
109         * @see #getModelEncoding()
110         */
111        public void setModelEncoding( final String value )
112        {
113            this.modelEncoding = value;
114        }
115    
116        /**
117         * Gets the file to write the model to.
118         *
119         * @return The file to write the model to or {@code null}.
120         *
121         * @see #setModelFile(java.io.File)
122         */
123        public File getModelFile()
124        {
125            return this.modelFile;
126        }
127    
128        /**
129         * Sets the file to write the model to.
130         *
131         * @param value The new file to write the model to or {@code null}.
132         *
133         * @see #getModelFile()
134         */
135        public void setModelFile( final File value )
136        {
137            this.modelFile = value;
138        }
139    
140        /**
141         * Gets the identifier of a specification to write.
142         *
143         * @return The identifier of a specification to write or {@code null}.
144         *
145         * @see #setSpecification(java.lang.String)
146         */
147        public String getSpecification()
148        {
149            return this.specification;
150        }
151    
152        /**
153         * Sets the identifier of a specification to write.
154         *
155         * @param value The new identifier of a specification to write or {@code null}.
156         *
157         * @see #getSpecification()
158         */
159        public void setSpecification( final String value )
160        {
161            this.specification = value;
162        }
163    
164        /**
165         * Gets the specification to write from a given model.
166         *
167         * @param model The model to get the specification to write from.
168         *
169         * @return The specification to write or {@code null}.
170         *
171         * @throws NullPointerException if {@code model} is {@code null}.
172         *
173         * @see #getSpecification()
174         */
175        public Specification getSpecification( final Model model )
176        {
177            if ( model == null )
178            {
179                throw new NullPointerException( "model" );
180            }
181    
182            Specification s = null;
183    
184            if ( this.getSpecification() != null )
185            {
186                final Modules modules = ModelHelper.getModules( model );
187    
188                if ( modules != null )
189                {
190                    s = modules.getSpecification( this.getSpecification() );
191                }
192    
193                if ( s == null )
194                {
195                    this.log( Messages.getMessage( "specificationNotFound", this.getSpecification() ), Project.MSG_WARN );
196                }
197            }
198    
199            return s;
200        }
201    
202        /**
203         * Gets the identifier of an implementation to write.
204         *
205         * @return The identifier of an implementation to write or {@code null}.
206         *
207         * @see #setImplementation(java.lang.String)
208         */
209        public String getImplementation()
210        {
211            return this.implementation;
212        }
213    
214        /**
215         * Sets the identifier of an implementation to write.
216         *
217         * @param value The new identifier of an implementation to write or {@code null}.
218         *
219         * @see #getImplementation()
220         */
221        public void setImplementation( final String value )
222        {
223            this.implementation = value;
224        }
225    
226        /**
227         * Gets the instance to write from a given model.
228         *
229         * @param model The model to get the instance to write from.
230         *
231         * @return The instance to write or {@code null}.
232         *
233         * @throws NullPointerException if {@code model} is {@code null}.
234         *
235         * @see #getImplementation()
236         */
237        public Instance getInstance( final Model model )
238        {
239            if ( model == null )
240            {
241                throw new NullPointerException( "model" );
242            }
243    
244            Instance i = null;
245    
246            if ( this.getImplementation() != null )
247            {
248                final Modules modules = ModelHelper.getModules( model );
249    
250                if ( modules != null )
251                {
252                    i = modules.getInstance( this.getImplementation() );
253                }
254    
255                if ( i == null )
256                {
257                    this.log( Messages.getMessage( "implementationNotFound", this.getImplementation() ), Project.MSG_WARN );
258                }
259            }
260    
261            return i;
262        }
263    
264        /**
265         * Gets the identifier of a module to write.
266         *
267         * @return The identifier of a module to write or {@code null}.
268         *
269         * @see #setModule(java.lang.String)
270         */
271        public String getModule()
272        {
273            return this.module;
274        }
275    
276        /**
277         * Sets the identifier of a module to write.
278         *
279         * @param value The new identifier of a module to write or {@code null}.
280         *
281         * @see #getModule()
282         */
283        public void setModule( final String value )
284        {
285            this.module = value;
286        }
287    
288        /**
289         * Gets the module to write from a given model.
290         *
291         * @param model The model to get the module to write from.
292         *
293         * @return The module to write or {@code null}.
294         *
295         * @throws NullPointerException if {@code model} is {@code null}.
296         *
297         * @see #getModule()
298         */
299        public Module getModule( final Model model )
300        {
301            if ( model == null )
302            {
303                throw new NullPointerException( "model" );
304            }
305    
306            Module m = null;
307    
308            if ( this.getModule() != null )
309            {
310                final Modules modules = ModelHelper.getModules( model );
311    
312                if ( modules != null )
313                {
314                    m = modules.getModule( this.getModule() );
315                }
316    
317                if ( m == null )
318                {
319                    this.log( Messages.getMessage( "moduleNotFound", this.getModule() ), Project.MSG_WARN );
320                }
321            }
322    
323            return m;
324        }
325    
326        /** {@inheritDoc} */
327        @Override
328        public void executeTask() throws BuildException
329        {
330            BufferedReader reader = null;
331            ProjectClassLoader classLoader = null;
332            boolean suppressExceptionOnClose = true;
333    
334            try
335            {
336                classLoader = this.newProjectClassLoader();
337                final ModelContext modelContext = this.newModelContext( classLoader );
338                final Model model = this.getModel( modelContext );
339                final Marshaller marshaller = modelContext.createMarshaller( this.getModel() );
340                final ModelValidationReport validationReport = modelContext.validateModel(
341                    this.getModel(), new JAXBSource( marshaller, new ObjectFactory().createModel( model ) ) );
342    
343                this.logValidationReport( modelContext, validationReport );
344                marshaller.setProperty( Marshaller.JAXB_ENCODING, this.getModelEncoding() );
345                marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
346    
347                Model displayModel = new Model();
348                displayModel.setIdentifier( this.getModel() );
349    
350                final Specification s = this.getSpecification( model );
351                if ( s != null )
352                {
353                    displayModel.getAny().add( s );
354                }
355    
356                final Instance i = this.getInstance( model );
357                if ( i != null )
358                {
359                    displayModel.getAny().add( i );
360                }
361    
362                final Module m = this.getModule( model );
363                if ( m != null )
364                {
365                    displayModel.getAny().add( m );
366                }
367    
368                if ( displayModel.getAny().isEmpty() )
369                {
370                    displayModel = model;
371                }
372    
373                if ( this.getModelFile() != null )
374                {
375                    this.log( Messages.getMessage( "writingModelObjects", this.getModel(),
376                                                   this.getModelFile().getAbsolutePath() ), Project.MSG_INFO );
377    
378                    marshaller.marshal( new ObjectFactory().createModel( displayModel ), this.getModelFile() );
379                }
380                else
381                {
382                    this.log( Messages.getMessage( "showingModelObjects", this.getModel() ), Project.MSG_INFO );
383    
384                    final StringWriter writer = new StringWriter();
385                    marshaller.marshal( new ObjectFactory().createModel( displayModel ), writer );
386    
387                    reader = new BufferedReader( new StringReader( writer.toString() ) );
388                    String line;
389    
390                    while ( ( line = reader.readLine() ) != null )
391                    {
392                        this.log( line, Project.MSG_INFO );
393                    }
394                }
395    
396                suppressExceptionOnClose = false;
397            }
398            catch ( final IOException e )
399            {
400                throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
401            }
402            catch ( final JAXBException e )
403            {
404                String message = Messages.getMessage( e );
405                if ( message == null )
406                {
407                    message = Messages.getMessage( e.getLinkedException() );
408                }
409    
410                throw new BuildException( message, e, this.getLocation() );
411            }
412            catch ( final ModelException e )
413            {
414                throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
415            }
416            finally
417            {
418                try
419                {
420                    if ( reader != null )
421                    {
422                        reader.close();
423                    }
424                }
425                catch ( final IOException e )
426                {
427                    if ( suppressExceptionOnClose )
428                    {
429                        this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
430                    }
431                    else
432                    {
433                        throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
434                    }
435                }
436                finally
437                {
438                    try
439                    {
440                        if ( classLoader != null )
441                        {
442                            classLoader.close();
443                        }
444                    }
445                    catch ( final IOException e )
446                    {
447                        if ( suppressExceptionOnClose )
448                        {
449                            this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
450                        }
451                        else
452                        {
453                            throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
454                        }
455                    }
456                }
457            }
458        }
459    
460        /** {@inheritDoc} */
461        @Override
462        public WriteModelTask clone()
463        {
464            return (WriteModelTask) super.clone();
465        }
466    
467    }