001/*
002 *   Copyright (C) 2005 Christian Schulte <cs@schulte.it>
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 5179 2016-04-15 02:58:23Z 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 5179 2016-04-15 02:58:23Z 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
452        try
453        {
454            classLoader = this.newProjectClassLoader();
455            final ModelContext modelContext = this.newModelContext( classLoader );
456            final Model model = this.getModel( modelContext );
457            final Marshaller marshaller = modelContext.createMarshaller( this.getModel() );
458            final ModelValidationReport validationReport = modelContext.validateModel(
459                this.getModel(), new JAXBSource( marshaller, new ObjectFactory().createModel( model ) ) );
460
461            this.logValidationReport( modelContext, validationReport );
462            marshaller.setProperty( Marshaller.JAXB_ENCODING, this.getModelEncoding() );
463            marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
464
465            Model displayModel = new Model();
466            displayModel.setIdentifier( this.getModel() );
467
468            final Specification s = this.getSpecification( model );
469            if ( s != null )
470            {
471                displayModel.getAny().add( new org.jomc.model.ObjectFactory().createSpecification( s ) );
472
473                if ( this.getSpecificationModelFile() != null )
474                {
475                    this.log( Messages.getMessage( "writingSpecification", s.getIdentifier(),
476                                                   this.getSpecificationModelFile().getAbsolutePath() ),
477                              Project.MSG_INFO );
478
479                    marshaller.marshal( new org.jomc.model.ObjectFactory().createSpecification( s ),
480                                        this.getSpecificationModelFile() );
481
482                }
483            }
484
485            final Instance i = this.getInstance( model );
486            if ( i != null )
487            {
488                displayModel.getAny().add( new org.jomc.model.ObjectFactory().createInstance( i ) );
489
490                if ( this.getInstanceModelFile() != null )
491                {
492                    this.log( Messages.getMessage( "writingInstance", i.getIdentifier(),
493                                                   this.getInstanceModelFile().getAbsolutePath() ),
494                              Project.MSG_INFO );
495
496                    marshaller.marshal( new org.jomc.model.ObjectFactory().createInstance( i ),
497                                        this.getInstanceModelFile() );
498
499                }
500            }
501
502            final Module m = this.getModule( model );
503            if ( m != null )
504            {
505                displayModel.getAny().add( new org.jomc.model.ObjectFactory().createModule( m ) );
506
507                if ( this.getModuleModelFile() != null )
508                {
509                    this.log( Messages.getMessage( "writingModule", m.getName(),
510                                                   this.getModuleModelFile().getAbsolutePath() ),
511                              Project.MSG_INFO );
512
513                    marshaller.marshal( new org.jomc.model.ObjectFactory().createModule( m ),
514                                        this.getModuleModelFile() );
515
516                }
517            }
518
519            if ( displayModel.getAny().isEmpty() )
520            {
521                displayModel = model;
522            }
523
524            if ( this.getModelFile() != null )
525            {
526                this.log( Messages.getMessage( "writingModelObjects", this.getModel(),
527                                               this.getModelFile().getAbsolutePath() ), Project.MSG_INFO );
528
529                marshaller.marshal( new ObjectFactory().createModel( displayModel ), this.getModelFile() );
530            }
531            else
532            {
533                this.log( Messages.getMessage( "showingModelObjects", this.getModel() ), Project.MSG_INFO );
534
535                final StringWriter writer = new StringWriter();
536                marshaller.marshal( new ObjectFactory().createModel( displayModel ), writer );
537
538                reader = new BufferedReader( new StringReader( writer.toString() ) );
539
540                for ( String line = reader.readLine(); line != null; line = reader.readLine() )
541                {
542                    this.log( line, Project.MSG_INFO );
543                }
544
545                reader.close();
546                reader = null;
547            }
548
549            classLoader.close();
550            classLoader = null;
551        }
552        catch ( final IOException e )
553        {
554            throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
555        }
556        catch ( final JAXBException e )
557        {
558            String message = Messages.getMessage( e );
559            if ( message == null )
560            {
561                message = Messages.getMessage( e.getLinkedException() );
562            }
563
564            throw new BuildException( message, e, this.getLocation() );
565        }
566        catch ( final ModelException e )
567        {
568            throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
569        }
570        finally
571        {
572            try
573            {
574                if ( reader != null )
575                {
576                    reader.close();
577                }
578            }
579            catch ( final IOException e )
580            {
581                this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
582            }
583            finally
584            {
585                try
586                {
587                    if ( classLoader != null )
588                    {
589                        classLoader.close();
590                    }
591                }
592                catch ( final IOException e )
593                {
594                    this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
595                }
596            }
597        }
598    }
599
600    /**
601     * {@inheritDoc}
602     */
603    @Override
604    public WriteModelTask clone()
605    {
606        return (WriteModelTask) super.clone();
607    }
608
609}