View Javadoc
1   /*
2    * Copyright (C) 2009 Christian Schulte <cs@schulte.it>
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: MergeModletsCommand.java 5263 2016-05-01 23:44:12Z schulte $
29   *
30   */
31  package org.jomc.cli.commands;
32  
33  import java.io.File;
34  import java.io.IOException;
35  import java.net.URL;
36  import java.util.Arrays;
37  import java.util.Enumeration;
38  import java.util.Iterator;
39  import java.util.List;
40  import java.util.Locale;
41  import java.util.logging.Level;
42  import javax.xml.bind.JAXBElement;
43  import javax.xml.bind.JAXBException;
44  import javax.xml.bind.Marshaller;
45  import javax.xml.bind.Unmarshaller;
46  import javax.xml.bind.util.JAXBResult;
47  import javax.xml.bind.util.JAXBSource;
48  import javax.xml.transform.Transformer;
49  import javax.xml.transform.TransformerException;
50  import javax.xml.transform.stream.StreamSource;
51  import org.apache.commons.cli.CommandLine;
52  import org.apache.commons.cli.Option;
53  import org.jomc.modlet.DefaultModletProvider;
54  import org.jomc.modlet.ModelContext;
55  import org.jomc.modlet.ModelException;
56  import org.jomc.modlet.ModelValidationReport;
57  import org.jomc.modlet.Modlet;
58  import org.jomc.modlet.ModletObject;
59  import org.jomc.modlet.Modlets;
60  import org.jomc.modlet.ObjectFactory;
61  
62  /**
63   * {@code merge-modlets} command implementation.
64   *
65   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
66   */
67  public final class MergeModletsCommand extends AbstractModletCommand
68  {
69  
70      /**
71       * Creates a new {@code MergeModletsCommand} instance.
72       */
73      public MergeModletsCommand()
74      {
75          super();
76      }
77  
78      @Override
79      public org.apache.commons.cli.Options getOptions()
80      {
81          final org.apache.commons.cli.Options options = super.getOptions();
82          Option option = (Option) Options.DOCUMENT_OPTION.clone();
83          option.setRequired( true );
84          options.addOption( option );
85  
86          options.addOption( Options.DOCUMENT_ENCODING_OPTION );
87          options.addOption( Options.STYLESHEET_OPTION );
88  
89          option = (Option) Options.MODLET_OPTION.clone();
90          option.setRequired( true );
91          options.addOption( option );
92  
93          options.addOption( Options.MODLET_VERSION_OPTION );
94          options.addOption( Options.MODLET_VENDOR_OPTION );
95          options.addOption( Options.MODLET_INCLUDES_OPTION );
96          options.addOption( Options.MODLET_EXCLUDES_OPTION );
97          options.addOption( Options.RESOURCES_OPTION );
98          return options;
99      }
100 
101     public String getName()
102     {
103         return "merge-modlets";
104     }
105 
106     public String getAbbreviatedName()
107     {
108         return "mmd";
109     }
110 
111     public String getShortDescription( final Locale locale )
112     {
113         return Messages.getMessage( "mergeModletsShortDescription" );
114     }
115 
116     public String getLongDescription( final Locale locale )
117     {
118         return null;
119     }
120 
121     protected void executeCommand( final CommandLine commandLine ) throws CommandExecutionException
122     {
123         if ( commandLine == null )
124         {
125             throw new NullPointerException( "commandLine" );
126         }
127 
128         CommandLineClassLoader classLoader = null;
129 
130         try
131         {
132             classLoader = new CommandLineClassLoader( commandLine );
133             final Modlets modlets = new Modlets();
134             final ModelContext context = this.createModelContext( commandLine, classLoader );
135             final Marshaller marshaller = context.createMarshaller( ModletObject.MODEL_PUBLIC_ID );
136             final Unmarshaller unmarshaller = context.createUnmarshaller( ModletObject.MODEL_PUBLIC_ID );
137 
138             if ( !commandLine.hasOption( Options.NO_MODLET_RESOURCE_VALIDATION_OPTION.getOpt() ) )
139             {
140                 unmarshaller.setSchema( context.createSchema( ModletObject.MODEL_PUBLIC_ID ) );
141             }
142 
143             File stylesheetFile = null;
144             if ( commandLine.hasOption( Options.STYLESHEET_OPTION.getOpt() ) )
145             {
146                 stylesheetFile = new File( commandLine.getOptionValue( Options.STYLESHEET_OPTION.getOpt() ) );
147             }
148 
149             String modletVersion = null;
150             if ( commandLine.hasOption( Options.MODLET_VERSION_OPTION.getOpt() ) )
151             {
152                 modletVersion = commandLine.getOptionValue( Options.MODLET_VERSION_OPTION.getOpt() );
153             }
154 
155             String modletVendor = null;
156             if ( commandLine.hasOption( Options.MODLET_VENDOR_OPTION.getOpt() ) )
157             {
158                 modletVendor = commandLine.getOptionValue( Options.MODLET_VENDOR_OPTION.getOpt() );
159             }
160 
161             if ( commandLine.hasOption( Options.DOCUMENTS_OPTION.getOpt() ) )
162             {
163                 for ( final File f : this.getDocumentFiles( commandLine ) )
164                 {
165                     if ( this.isLoggable( Level.FINEST ) )
166                     {
167                         this.log( Level.FINEST, Messages.getMessage( "readingResource", f.getAbsolutePath() ), null );
168                     }
169 
170                     Object o = unmarshaller.unmarshal( f );
171                     if ( o instanceof JAXBElement<?> )
172                     {
173                         o = ( (JAXBElement<?>) o ).getValue();
174                     }
175 
176                     if ( o instanceof Modlet )
177                     {
178                         modlets.getModlet().add( (Modlet) o );
179                     }
180                     else if ( o instanceof Modlets )
181                     {
182                         modlets.getModlet().addAll( ( (Modlets) o ).getModlet() );
183                     }
184                     else if ( this.isLoggable( Level.WARNING ) )
185                     {
186                         this.log( Level.WARNING,
187                                   Messages.getMessage( "failureProcessing", f.getAbsolutePath(), o.toString() ),
188                                   null );
189 
190                     }
191                 }
192             }
193 
194             if ( commandLine.hasOption( Options.CLASSPATH_OPTION.getOpt() ) )
195             {
196                 String[] resourceNames = null;
197 
198                 if ( commandLine.hasOption( Options.RESOURCES_OPTION.getOpt() ) )
199                 {
200                     resourceNames = commandLine.getOptionValues( Options.RESOURCES_OPTION.getOpt() );
201                 }
202 
203                 if ( resourceNames == null )
204                 {
205                     resourceNames = new String[]
206                     {
207                         DefaultModletProvider.getDefaultModletLocation()
208                     };
209                 }
210 
211                 for ( final String resource : resourceNames )
212                 {
213                     for ( final Enumeration<URL> e = classLoader.getResources( resource ); e.hasMoreElements(); )
214                     {
215                         final URL url = e.nextElement();
216 
217                         if ( this.isLoggable( Level.FINEST ) )
218                         {
219                             this.log( Level.FINEST,
220                                       Messages.getMessage( "readingResource", url.toExternalForm() ),
221                                       null );
222 
223                         }
224 
225                         Object o = unmarshaller.unmarshal( url );
226                         if ( o instanceof JAXBElement<?> )
227                         {
228                             o = ( (JAXBElement<?>) o ).getValue();
229                         }
230 
231                         if ( o instanceof Modlet )
232                         {
233                             modlets.getModlet().add( (Modlet) o );
234                         }
235                         else if ( o instanceof Modlets )
236                         {
237                             modlets.getModlet().addAll( ( (Modlets) o ).getModlet() );
238                         }
239                         else if ( this.isLoggable( Level.WARNING ) )
240                         {
241                             this.log( Level.WARNING,
242                                       Messages.getMessage( "failureProcessing", url.toExternalForm(), o.toString() ),
243                                       null );
244 
245                         }
246                     }
247                 }
248             }
249 
250             if ( commandLine.hasOption( Options.MODLET_INCLUDES_OPTION.getOpt() ) )
251             {
252                 final String[] values = commandLine.getOptionValues( Options.MODLET_INCLUDES_OPTION.getOpt() );
253 
254                 if ( values != null )
255                 {
256                     final List<String> includes = Arrays.asList( values );
257 
258                     for ( final Iterator<Modlet> it = modlets.getModlet().iterator(); it.hasNext(); )
259                     {
260                         final Modlet m = it.next();
261 
262                         if ( !includes.contains( m.getName() ) )
263                         {
264                             this.log( Level.INFO,
265                                       Messages.getMessage( "modletNameExclusionInfo", m.getName() ),
266                                       null );
267 
268                             it.remove();
269                         }
270                         else
271                         {
272                             this.log( Level.INFO,
273                                       Messages.getMessage( "modletNameInclusionInfo", m.getName() ),
274                                       null );
275 
276                         }
277                     }
278                 }
279             }
280 
281             if ( commandLine.hasOption( Options.MODLET_EXCLUDES_OPTION.getOpt() ) )
282             {
283                 final String[] values = commandLine.getOptionValues( Options.MODLET_EXCLUDES_OPTION.getOpt() );
284 
285                 if ( values != null )
286                 {
287                     for ( final String exclude : values )
288                     {
289                         final Modlet m = modlets.getModlet( exclude );
290 
291                         if ( m != null )
292                         {
293                             this.log( Level.INFO,
294                                       Messages.getMessage( "modletNameExclusionInfo", m.getName() ),
295                                       null );
296 
297                             modlets.getModlet().remove( m );
298                         }
299                     }
300                 }
301             }
302 
303             final ModelValidationReport validationReport =
304                 context.validateModel( ModletObject.MODEL_PUBLIC_ID,
305                                        new JAXBSource( marshaller, new ObjectFactory().createModlets( modlets ) ) );
306 
307             this.log( validationReport, marshaller );
308 
309             if ( !validationReport.isModelValid() )
310             {
311                 throw new CommandExecutionException( Messages.getMessage( "invalidModel",
312                                                                           ModletObject.MODEL_PUBLIC_ID ) );
313 
314             }
315 
316             Modlet mergedModlet = modlets.getMergedModlet(
317                 commandLine.getOptionValue( Options.MODLET_OPTION.getOpt() ), this.getModel( commandLine ) );
318 
319             mergedModlet.setVersion( modletVersion );
320             mergedModlet.setVendor( modletVendor );
321 
322             final File modletFile = new File( commandLine.getOptionValue( Options.DOCUMENT_OPTION.getOpt() ) );
323 
324             if ( stylesheetFile != null )
325             {
326                 final Transformer transformer = this.createTransformer( new StreamSource( stylesheetFile ) );
327                 final JAXBSource source =
328                     new JAXBSource( marshaller, new ObjectFactory().createModlet( mergedModlet ) );
329 
330                 final JAXBResult result = new JAXBResult( unmarshaller );
331                 unmarshaller.setSchema( null );
332                 transformer.transform( source, result );
333 
334                 if ( result.getResult() instanceof JAXBElement<?>
335                          && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Modlet )
336                 {
337                     mergedModlet = (Modlet) ( (JAXBElement<?>) result.getResult() ).getValue();
338                 }
339                 else
340                 {
341                     throw new CommandExecutionException( Messages.getMessage( "illegalTransformationResultError",
342                                                                               stylesheetFile.getAbsolutePath() ) );
343 
344                 }
345             }
346 
347             marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
348 
349             if ( commandLine.hasOption( Options.DOCUMENT_ENCODING_OPTION.getOpt() ) )
350             {
351                 marshaller.setProperty( Marshaller.JAXB_ENCODING,
352                                         commandLine.getOptionValue( Options.DOCUMENT_ENCODING_OPTION.getOpt() ) );
353 
354             }
355 
356             marshaller.setSchema( context.createSchema( ModletObject.MODEL_PUBLIC_ID ) );
357             marshaller.marshal( new ObjectFactory().createModlet( mergedModlet ), modletFile );
358 
359             if ( this.isLoggable( Level.INFO ) )
360             {
361                 this.log( Level.INFO, Messages.getMessage( "writingResource", modletFile.getAbsolutePath() ), null );
362             }
363 
364             classLoader.close();
365             classLoader = null;
366         }
367         catch ( final IOException e )
368         {
369             throw new CommandExecutionException( Messages.getMessage( e ), e );
370         }
371         catch ( final TransformerException e )
372         {
373             String message = Messages.getMessage( e );
374             if ( message == null )
375             {
376                 message = Messages.getMessage( e.getException() );
377             }
378 
379             throw new CommandExecutionException( message, e );
380         }
381         catch ( final JAXBException e )
382         {
383             String message = Messages.getMessage( e );
384             if ( message == null )
385             {
386                 message = Messages.getMessage( e.getLinkedException() );
387             }
388 
389             throw new CommandExecutionException( message, e );
390         }
391         catch ( final ModelException e )
392         {
393             throw new CommandExecutionException( Messages.getMessage( e ), e );
394         }
395         finally
396         {
397             try
398             {
399                 if ( classLoader != null )
400                 {
401                     classLoader.close();
402                 }
403             }
404             catch ( final IOException e )
405             {
406                 this.log( Level.SEVERE, Messages.getMessage( e ), e );
407             }
408         }
409     }
410 
411 }