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 4613 2012-09-22 10:07:08Z schulte $
029 *
030 */
031package org.jomc.ant;
032
033import java.io.BufferedReader;
034import java.io.ByteArrayOutputStream;
035import java.io.File;
036import java.io.IOException;
037import java.io.OutputStreamWriter;
038import java.io.StringReader;
039import java.io.StringWriter;
040import java.util.logging.Level;
041import javax.xml.bind.JAXBException;
042import javax.xml.bind.Marshaller;
043import javax.xml.bind.util.JAXBSource;
044import org.apache.tools.ant.BuildException;
045import org.apache.tools.ant.Project;
046import org.jomc.model.Instance;
047import org.jomc.model.Module;
048import org.jomc.model.Modules;
049import org.jomc.model.Specification;
050import org.jomc.model.modlet.ModelHelper;
051import org.jomc.modlet.Model;
052import org.jomc.modlet.ModelContext;
053import org.jomc.modlet.ModelException;
054import org.jomc.modlet.ModelValidationReport;
055import org.jomc.modlet.ObjectFactory;
056
057/**
058 * Task for writing model objects.
059 *
060 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
061 * @version $JOMC: WriteModelTask.java 4613 2012-09-22 10:07:08Z schulte $
062 */
063public 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}