001/*
002 *   Copyright (C) Christian Schulte <cs@schulte.it>, 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 5043 2015-05-27 07:03:39Z 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 5043 2015-05-27 07:03:39Z schulte $
062 */
063public final class WriteModelTask extends JomcModelTask
064{
065
066    /**
067     * The identifier of a specification to write.
068     */
069    private String specification;
070
071    /**
072     * The identifier of an implementation to write.
073     */
074    private String implementation;
075
076    /**
077     * The name of a module to write.
078     */
079    private String module;
080
081    /**
082     * The encoding to use when writing the model.
083     */
084    private String modelEncoding;
085
086    /**
087     * File to write the model to.
088     */
089    private File modelFile;
090
091    /**
092     * File to write the specification to.
093     *
094     * @since 1.6
095     */
096    private File specificationModelFile;
097
098    /**
099     * File to write the instance to.
100     *
101     * @since 1.6
102     */
103    private File instanceModelFile;
104
105    /**
106     * File to write the module to.
107     *
108     * @since 1.6
109     */
110    private File moduleModelFile;
111
112    /**
113     * Creates a new {@code WriteModelTask} instance.
114     */
115    public WriteModelTask()
116    {
117        super();
118    }
119
120    /**
121     * Gets the encoding of the model resource.
122     *
123     * @return The encoding of the model resource.
124     *
125     * @see #setModelEncoding(java.lang.String)
126     */
127    public String getModelEncoding()
128    {
129        if ( this.modelEncoding == null )
130        {
131            this.modelEncoding = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
132        }
133
134        return this.modelEncoding;
135    }
136
137    /**
138     * Sets the encoding of the model resource.
139     *
140     * @param value The new encoding of the model resource or {@code null}.
141     *
142     * @see #getModelEncoding()
143     */
144    public void setModelEncoding( final String value )
145    {
146        this.modelEncoding = value;
147    }
148
149    /**
150     * Gets the file to write the model to.
151     *
152     * @return The file to write the model to or {@code null}.
153     *
154     * @see #setModelFile(java.io.File)
155     */
156    public File getModelFile()
157    {
158        return this.modelFile;
159    }
160
161    /**
162     * Sets the file to write the model to.
163     *
164     * @param value The new file to write the model to or {@code null}.
165     *
166     * @see #getModelFile()
167     */
168    public void setModelFile( final File value )
169    {
170        this.modelFile = value;
171    }
172
173    /**
174     * Gets the file to write the specification to.
175     *
176     * @return The file to write the specification to or {@code null}.
177     *
178     * @see #setSpecificationModelFile(java.io.File)
179     *
180     * @since 1.6
181     */
182    public File getSpecificationModelFile()
183    {
184        return this.specificationModelFile;
185    }
186
187    /**
188     * Sets the file to write the specification to.
189     *
190     * @param value The new file to write the specification to or {@code null}.
191     *
192     * @see #getSpecificationModelFile()
193     *
194     * @since 1.6
195     */
196    public void setSpecificationModelFile( final File value )
197    {
198        this.specificationModelFile = value;
199    }
200
201    /**
202     * Gets the file to write the instance to.
203     *
204     * @return The file to write the instance to or {@code null}.
205     *
206     * @see #setInstanceModelFile(java.io.File)
207     *
208     * @since 1.6
209     */
210    public File getInstanceModelFile()
211    {
212        return this.instanceModelFile;
213    }
214
215    /**
216     * Sets the file to write the instance to.
217     *
218     * @param value The new file to write the instance to or {@code null}.
219     *
220     * @see #getInstanceModelFile()
221     *
222     * @since 1.6
223     */
224    public void setInstanceModelFile( final File value )
225    {
226        this.instanceModelFile = value;
227    }
228
229    /**
230     * Gets the file to write the module to.
231     *
232     * @return The file to write the module to or {@code null}.
233     *
234     * @see #setModuleModelFile(java.io.File)
235     *
236     * @since 1.6
237     */
238    public File getModuleModelFile()
239    {
240        return this.moduleModelFile;
241    }
242
243    /**
244     * Sets the file to write the module to.
245     *
246     * @param value The new file to write the module to or {@code null}.
247     *
248     * @see #getModuleModelFile()
249     *
250     * @since 1.6
251     */
252    public void setModuleModelFile( final File value )
253    {
254        this.moduleModelFile = value;
255    }
256
257    /**
258     * Gets the identifier of a specification to write.
259     *
260     * @return The identifier of a specification to write or {@code null}.
261     *
262     * @see #setSpecification(java.lang.String)
263     */
264    public String getSpecification()
265    {
266        return this.specification;
267    }
268
269    /**
270     * Sets the identifier of a specification to write.
271     *
272     * @param value The new identifier of a specification to write or {@code null}.
273     *
274     * @see #getSpecification()
275     */
276    public void setSpecification( final String value )
277    {
278        this.specification = value;
279    }
280
281    /**
282     * Gets the specification to write from a given model.
283     *
284     * @param model The model to get the specification to write from.
285     *
286     * @return The specification to write or {@code null}.
287     *
288     * @throws NullPointerException if {@code model} is {@code null}.
289     *
290     * @see #getSpecification()
291     */
292    public Specification getSpecification( final Model model )
293    {
294        if ( model == null )
295        {
296            throw new NullPointerException( "model" );
297        }
298
299        Specification s = null;
300
301        if ( this.getSpecification() != null )
302        {
303            final Modules modules = ModelHelper.getModules( model );
304
305            if ( modules != null )
306            {
307                s = modules.getSpecification( this.getSpecification() );
308            }
309
310            if ( s == null )
311            {
312                this.log( Messages.getMessage( "specificationNotFound", this.getSpecification() ), Project.MSG_WARN );
313            }
314        }
315
316        return s;
317    }
318
319    /**
320     * Gets the identifier of an implementation to write.
321     *
322     * @return The identifier of an implementation to write or {@code null}.
323     *
324     * @see #setImplementation(java.lang.String)
325     */
326    public String getImplementation()
327    {
328        return this.implementation;
329    }
330
331    /**
332     * Sets the identifier of an implementation to write.
333     *
334     * @param value The new identifier of an implementation to write or {@code null}.
335     *
336     * @see #getImplementation()
337     */
338    public void setImplementation( final String value )
339    {
340        this.implementation = value;
341    }
342
343    /**
344     * Gets the instance to write from a given model.
345     *
346     * @param model The model to get the instance to write from.
347     *
348     * @return The instance to write or {@code null}.
349     *
350     * @throws NullPointerException if {@code model} is {@code null}.
351     *
352     * @see #getImplementation()
353     */
354    public Instance getInstance( final Model model )
355    {
356        if ( model == null )
357        {
358            throw new NullPointerException( "model" );
359        }
360
361        Instance i = null;
362
363        if ( this.getImplementation() != null )
364        {
365            final Modules modules = ModelHelper.getModules( model );
366
367            if ( modules != null )
368            {
369                i = modules.getInstance( this.getImplementation() );
370            }
371
372            if ( i == null )
373            {
374                this.log( Messages.getMessage( "implementationNotFound", this.getImplementation() ), Project.MSG_WARN );
375            }
376        }
377
378        return i;
379    }
380
381    /**
382     * Gets the identifier of a module to write.
383     *
384     * @return The identifier of a module to write or {@code null}.
385     *
386     * @see #setModule(java.lang.String)
387     */
388    public String getModule()
389    {
390        return this.module;
391    }
392
393    /**
394     * Sets the identifier of a module to write.
395     *
396     * @param value The new identifier of a module to write or {@code null}.
397     *
398     * @see #getModule()
399     */
400    public void setModule( final String value )
401    {
402        this.module = value;
403    }
404
405    /**
406     * Gets the module to write from a given model.
407     *
408     * @param model The model to get the module to write from.
409     *
410     * @return The module to write or {@code null}.
411     *
412     * @throws NullPointerException if {@code model} is {@code null}.
413     *
414     * @see #getModule()
415     */
416    public Module getModule( final Model model )
417    {
418        if ( model == null )
419        {
420            throw new NullPointerException( "model" );
421        }
422
423        Module m = null;
424
425        if ( this.getModule() != null )
426        {
427            final Modules modules = ModelHelper.getModules( model );
428
429            if ( modules != null )
430            {
431                m = modules.getModule( this.getModule() );
432            }
433
434            if ( m == null )
435            {
436                this.log( Messages.getMessage( "moduleNotFound", this.getModule() ), Project.MSG_WARN );
437            }
438        }
439
440        return m;
441    }
442
443    /**
444     * {@inheritDoc}
445     */
446    @Override
447    public void executeTask() throws BuildException
448    {
449        BufferedReader reader = null;
450        ProjectClassLoader classLoader = null;
451        boolean suppressExceptionOnClose = true;
452
453        try
454        {
455            classLoader = this.newProjectClassLoader();
456            final ModelContext modelContext = this.newModelContext( classLoader );
457            final Model model = this.getModel( modelContext );
458            final Marshaller marshaller = modelContext.createMarshaller( this.getModel() );
459            final ModelValidationReport validationReport = modelContext.validateModel(
460                this.getModel(), new JAXBSource( marshaller, new ObjectFactory().createModel( model ) ) );
461
462            this.logValidationReport( modelContext, validationReport );
463            marshaller.setProperty( Marshaller.JAXB_ENCODING, this.getModelEncoding() );
464            marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
465
466            Model displayModel = new Model();
467            displayModel.setIdentifier( this.getModel() );
468
469            final Specification s = this.getSpecification( model );
470            if ( s != null )
471            {
472                displayModel.getAny().add( new org.jomc.model.ObjectFactory().createSpecification( s ) );
473
474                if ( this.getSpecificationModelFile() != null )
475                {
476                    this.log( Messages.getMessage( "writingSpecification", s.getIdentifier(),
477                                                   this.getSpecificationModelFile().getAbsolutePath() ),
478                              Project.MSG_INFO );
479
480                    marshaller.marshal( new org.jomc.model.ObjectFactory().createSpecification( s ),
481                                        this.getSpecificationModelFile() );
482
483                }
484            }
485
486            final Instance i = this.getInstance( model );
487            if ( i != null )
488            {
489                displayModel.getAny().add( new org.jomc.model.ObjectFactory().createInstance( i ) );
490
491                if ( this.getInstanceModelFile() != null )
492                {
493                    this.log( Messages.getMessage( "writingInstance", i.getIdentifier(),
494                                                   this.getInstanceModelFile().getAbsolutePath() ),
495                              Project.MSG_INFO );
496
497                    marshaller.marshal( new org.jomc.model.ObjectFactory().createInstance( i ),
498                                        this.getInstanceModelFile() );
499
500                }
501            }
502
503            final Module m = this.getModule( model );
504            if ( m != null )
505            {
506                displayModel.getAny().add( new org.jomc.model.ObjectFactory().createModule( m ) );
507
508                if ( this.getModuleModelFile() != null )
509                {
510                    this.log( Messages.getMessage( "writingModule", m.getName(),
511                                                   this.getModuleModelFile().getAbsolutePath() ),
512                              Project.MSG_INFO );
513
514                    marshaller.marshal( new org.jomc.model.ObjectFactory().createModule( m ),
515                                        this.getModuleModelFile() );
516
517                }
518            }
519
520            if ( displayModel.getAny().isEmpty() )
521            {
522                displayModel = model;
523            }
524
525            if ( this.getModelFile() != null )
526            {
527                this.log( Messages.getMessage( "writingModelObjects", this.getModel(),
528                                               this.getModelFile().getAbsolutePath() ), Project.MSG_INFO );
529
530                marshaller.marshal( new ObjectFactory().createModel( displayModel ), this.getModelFile() );
531            }
532            else
533            {
534                this.log( Messages.getMessage( "showingModelObjects", this.getModel() ), Project.MSG_INFO );
535
536                final StringWriter writer = new StringWriter();
537                marshaller.marshal( new ObjectFactory().createModel( displayModel ), writer );
538
539                reader = new BufferedReader( new StringReader( writer.toString() ) );
540                String line;
541
542                while ( ( line = reader.readLine() ) != null )
543                {
544                    this.log( line, Project.MSG_INFO );
545                }
546            }
547
548            suppressExceptionOnClose = false;
549        }
550        catch ( final IOException e )
551        {
552            throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
553        }
554        catch ( final JAXBException e )
555        {
556            String message = Messages.getMessage( e );
557            if ( message == null )
558            {
559                message = Messages.getMessage( e.getLinkedException() );
560            }
561
562            throw new BuildException( message, e, this.getLocation() );
563        }
564        catch ( final ModelException e )
565        {
566            throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
567        }
568        finally
569        {
570            try
571            {
572                if ( reader != null )
573                {
574                    reader.close();
575                }
576            }
577            catch ( final IOException e )
578            {
579                if ( suppressExceptionOnClose )
580                {
581                    this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
582                }
583                else
584                {
585                    throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
586                }
587            }
588            finally
589            {
590                try
591                {
592                    if ( classLoader != null )
593                    {
594                        classLoader.close();
595                    }
596                }
597                catch ( final IOException e )
598                {
599                    if ( suppressExceptionOnClose )
600                    {
601                        this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
602                    }
603                    else
604                    {
605                        throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
606                    }
607                }
608            }
609        }
610    }
611
612    /**
613     * {@inheritDoc}
614     */
615    @Override
616    public WriteModelTask clone()
617    {
618        return (WriteModelTask) super.clone();
619    }
620
621}