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: MergeModulesCommand.java 5251 2016-04-25 19:46:04Z 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.model.Module;
54  import org.jomc.model.Modules;
55  import org.jomc.model.ObjectFactory;
56  import org.jomc.model.modlet.DefaultModelProvider;
57  import org.jomc.modlet.ModelContext;
58  import org.jomc.modlet.ModelException;
59  import org.jomc.modlet.ModelValidationReport;
60  
61  /**
62   * {@code merge-modules} command implementation.
63   *
64   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
65   */
66  public final class MergeModulesCommand extends AbstractModelCommand
67  {
68  
69      /**
70       * Creates a new {@code MergeModulesCommand} instance.
71       */
72      public MergeModulesCommand()
73      {
74          super();
75      }
76  
77      @Override
78      public org.apache.commons.cli.Options getOptions()
79      {
80          final org.apache.commons.cli.Options options = super.getOptions();
81          Option option = (Option) Options.DOCUMENT_OPTION.clone();
82          option.setRequired( true );
83          options.addOption( option );
84  
85          options.addOption( Options.DOCUMENT_ENCODING_OPTION );
86          options.addOption( Options.STYLESHEET_OPTION );
87  
88          option = (Option) Options.MODULE_OPTION.clone();
89          option.setRequired( true );
90          options.addOption( option );
91  
92          options.addOption( Options.MODULE_VERSION_OPTION );
93          options.addOption( Options.MODULE_VENDOR_OPTION );
94          options.addOption( Options.MODULE_INCLUDES_OPTION );
95          options.addOption( Options.MODULE_EXCLUDES_OPTION );
96          options.addOption( Options.RESOURCES_OPTION );
97          return options;
98      }
99  
100     public String getName()
101     {
102         return "merge-modules";
103     }
104 
105     public String getAbbreviatedName()
106     {
107         return "mm";
108     }
109 
110     public String getShortDescription( final Locale locale )
111     {
112         return Messages.getMessage( "mergeModulesShortDescription" );
113     }
114 
115     public String getLongDescription( final Locale locale )
116     {
117         return null;
118     }
119 
120     protected void executeCommand( final CommandLine commandLine ) throws CommandExecutionException
121     {
122         if ( commandLine == null )
123         {
124             throw new NullPointerException( "commandLine" );
125         }
126 
127         CommandLineClassLoader classLoader = null;
128 
129         try
130         {
131             classLoader = new CommandLineClassLoader( commandLine );
132             final Modules modules = new Modules();
133             final ModelContext context = this.createModelContext( commandLine, classLoader );
134             final String model = this.getModel( commandLine );
135             final Marshaller marshaller = context.createMarshaller( model );
136             final Unmarshaller unmarshaller = context.createUnmarshaller( model );
137 
138             if ( !commandLine.hasOption( Options.NO_MODLET_RESOURCE_VALIDATION_OPTION.getOpt() ) )
139             {
140                 unmarshaller.setSchema( context.createSchema( model ) );
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 moduleVersion = null;
150             if ( commandLine.hasOption( Options.MODULE_VERSION_OPTION.getOpt() ) )
151             {
152                 moduleVersion = commandLine.getOptionValue( Options.MODULE_VERSION_OPTION.getOpt() );
153             }
154 
155             String moduleVendor = null;
156             if ( commandLine.hasOption( Options.MODULE_VENDOR_OPTION.getOpt() ) )
157             {
158                 moduleVendor = commandLine.getOptionValue( Options.MODULE_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 Module )
177                     {
178                         modules.getModule().add( (Module) o );
179                     }
180                     else if ( o instanceof Modules )
181                     {
182                         modules.getModule().addAll( ( (Modules) o ).getModule() );
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                         DefaultModelProvider.getDefaultModuleLocation()
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 Module )
232                         {
233                             modules.getModule().add( (Module) o );
234                         }
235                         else if ( o instanceof Modules )
236                         {
237                             modules.getModule().addAll( ( (Modules) o ).getModule() );
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.MODULE_INCLUDES_OPTION.getOpt() ) )
251             {
252                 final String[] values = commandLine.getOptionValues( Options.MODULE_INCLUDES_OPTION.getOpt() );
253 
254                 if ( values != null )
255                 {
256                     final List<String> includes = Arrays.asList( values );
257 
258                     for ( final Iterator<Module> it = modules.getModule().iterator(); it.hasNext(); )
259                     {
260                         final Module m = it.next();
261                         if ( !includes.contains( m.getName() ) )
262                         {
263                             this.log( Level.INFO,
264                                       Messages.getMessage( "moduleExclusionInfo", m.getName() ),
265                                       null );
266 
267                             it.remove();
268                         }
269                         else
270                         {
271                             this.log( Level.INFO,
272                                       Messages.getMessage( "moduleInclusionInfo", m.getName() ),
273                                       null );
274 
275                         }
276                     }
277                 }
278             }
279 
280             if ( commandLine.hasOption( Options.MODULE_EXCLUDES_OPTION.getOpt() ) )
281             {
282                 final String[] values = commandLine.getOptionValues( Options.MODULE_EXCLUDES_OPTION.getOpt() );
283 
284                 if ( values != null )
285                 {
286                     for ( final String exclude : values )
287                     {
288                         final Module m = modules.getModule( exclude );
289 
290                         if ( m != null )
291                         {
292                             this.log( Level.INFO,
293                                       Messages.getMessage( "moduleExclusionInfo", m.getName() ),
294                                       null );
295 
296                             modules.getModule().remove( m );
297                         }
298                     }
299                 }
300             }
301 
302             Module classpathModule = null;
303             if ( !commandLine.hasOption( Options.NO_CLASSPATH_RESOLUTION_OPTION.getOpt() ) )
304             {
305                 classpathModule = modules.getClasspathModule( Modules.getDefaultClasspathModuleName(), classLoader );
306                 if ( classpathModule != null && modules.getModule( Modules.getDefaultClasspathModuleName() ) == null )
307                 {
308                     modules.getModule().add( classpathModule );
309                 }
310                 else
311                 {
312                     classpathModule = null;
313                 }
314             }
315 
316             final ModelValidationReport validationReport = context.validateModel(
317                 model, new JAXBSource( marshaller, new ObjectFactory().createModules( modules ) ) );
318 
319             this.log( validationReport, marshaller );
320 
321             if ( !validationReport.isModelValid() )
322             {
323                 throw new CommandExecutionException( Messages.getMessage( "invalidModel", model ) );
324             }
325 
326             if ( classpathModule != null )
327             {
328                 modules.getModule().remove( classpathModule );
329             }
330 
331             Module mergedModule =
332                 modules.getMergedModule( commandLine.getOptionValue( Options.MODULE_OPTION.getOpt() ) );
333 
334             mergedModule.setVersion( moduleVersion );
335             mergedModule.setVendor( moduleVendor );
336 
337             final File moduleFile = new File( commandLine.getOptionValue( Options.DOCUMENT_OPTION.getOpt() ) );
338 
339             if ( stylesheetFile != null )
340             {
341                 final Transformer transformer = this.createTransformer( new StreamSource( stylesheetFile ) );
342                 final JAXBSource source =
343                     new JAXBSource( marshaller, new ObjectFactory().createModule( mergedModule ) );
344 
345                 final JAXBResult result = new JAXBResult( unmarshaller );
346                 unmarshaller.setSchema( null );
347                 transformer.transform( source, result );
348 
349                 if ( result.getResult() instanceof JAXBElement<?>
350                          && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Module )
351                 {
352                     mergedModule = (Module) ( (JAXBElement<?>) result.getResult() ).getValue();
353                 }
354                 else
355                 {
356                     throw new CommandExecutionException( Messages.getMessage( "illegalTransformationResultError",
357                                                                               stylesheetFile.getAbsolutePath() ) );
358 
359                 }
360             }
361 
362             marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
363 
364             if ( commandLine.hasOption( Options.DOCUMENT_ENCODING_OPTION.getOpt() ) )
365             {
366                 marshaller.setProperty( Marshaller.JAXB_ENCODING,
367                                         commandLine.getOptionValue( Options.DOCUMENT_ENCODING_OPTION.getOpt() ) );
368 
369             }
370 
371             marshaller.setSchema( context.createSchema( model ) );
372             marshaller.marshal( new ObjectFactory().createModule( mergedModule ), moduleFile );
373 
374             if ( this.isLoggable( Level.INFO ) )
375             {
376                 this.log( Level.INFO, Messages.getMessage( "writingResource", moduleFile.getAbsolutePath() ), null );
377             }
378 
379             classLoader.close();
380             classLoader = null;
381         }
382         catch ( final IOException e )
383         {
384             throw new CommandExecutionException( Messages.getMessage( e ), e );
385         }
386         catch ( final TransformerException e )
387         {
388             String message = Messages.getMessage( e );
389             if ( message == null )
390             {
391                 message = Messages.getMessage( e.getException() );
392             }
393 
394             throw new CommandExecutionException( message, e );
395         }
396         catch ( final JAXBException e )
397         {
398             String message = Messages.getMessage( e );
399             if ( message == null )
400             {
401                 message = Messages.getMessage( e.getLinkedException() );
402             }
403 
404             throw new CommandExecutionException( message, e );
405         }
406         catch ( final ModelException e )
407         {
408             throw new CommandExecutionException( Messages.getMessage( e ), e );
409         }
410         finally
411         {
412             try
413             {
414                 if ( classLoader != null )
415                 {
416                     classLoader.close();
417                 }
418             }
419             catch ( final IOException e )
420             {
421                 this.log( Level.SEVERE, Messages.getMessage( e ), e );
422             }
423         }
424     }
425 
426 }