1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package org.jomc.ant;
32
33 import java.io.ByteArrayOutputStream;
34 import java.io.File;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.OutputStreamWriter;
38 import java.net.SocketTimeoutException;
39 import java.net.URISyntaxException;
40 import java.net.URL;
41 import java.net.URLConnection;
42 import java.util.ArrayList;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.LinkedList;
46 import java.util.List;
47 import java.util.Set;
48 import java.util.logging.Level;
49 import javax.xml.bind.JAXBElement;
50 import javax.xml.bind.JAXBException;
51 import javax.xml.bind.Marshaller;
52 import javax.xml.bind.Unmarshaller;
53 import javax.xml.bind.util.JAXBResult;
54 import javax.xml.bind.util.JAXBSource;
55 import javax.xml.transform.Source;
56 import javax.xml.transform.Transformer;
57 import javax.xml.transform.TransformerConfigurationException;
58 import javax.xml.transform.TransformerException;
59 import javax.xml.transform.stream.StreamSource;
60 import org.apache.tools.ant.BuildException;
61 import org.apache.tools.ant.Project;
62 import org.jomc.ant.types.NameType;
63 import org.jomc.ant.types.ResourceType;
64 import org.jomc.ant.types.TransformerResourceType;
65 import org.jomc.model.Module;
66 import org.jomc.model.Modules;
67 import org.jomc.model.ObjectFactory;
68 import org.jomc.model.modlet.DefaultModelProvider;
69 import org.jomc.modlet.ModelContext;
70 import org.jomc.modlet.ModelException;
71 import org.jomc.modlet.ModelValidationReport;
72
73
74
75
76
77
78
79 public final class MergeModulesTask extends JomcModelTask
80 {
81
82
83 private String moduleEncoding;
84
85
86 private File moduleFile;
87
88
89 private String moduleName;
90
91
92 private String moduleVersion;
93
94
95 private String moduleVendor;
96
97
98 private Set<NameType> moduleIncludes;
99
100
101 private Set<NameType> moduleExcludes;
102
103
104 private List<TransformerResourceType> modelObjectStylesheetResources;
105
106
107 public MergeModulesTask()
108 {
109 super();
110 }
111
112
113
114
115
116
117
118
119 public File getModuleFile()
120 {
121 return this.moduleFile;
122 }
123
124
125
126
127
128
129
130
131 public void setModuleFile( final File value )
132 {
133 this.moduleFile = value;
134 }
135
136
137
138
139
140
141
142
143 public String getModuleEncoding()
144 {
145 if ( this.moduleEncoding == null )
146 {
147 this.moduleEncoding = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
148 }
149
150 return this.moduleEncoding;
151 }
152
153
154
155
156
157
158
159
160 public void setModuleEncoding( final String value )
161 {
162 this.moduleEncoding = value;
163 }
164
165
166
167
168
169
170
171
172 public String getModuleName()
173 {
174 return this.moduleName;
175 }
176
177
178
179
180
181
182
183
184 public void setModuleName( final String value )
185 {
186 this.moduleName = value;
187 }
188
189
190
191
192
193
194
195
196 public String getModuleVersion()
197 {
198 return this.moduleVersion;
199 }
200
201
202
203
204
205
206
207
208 public void setModuleVersion( final String value )
209 {
210 this.moduleVersion = value;
211 }
212
213
214
215
216
217
218
219
220 public String getModuleVendor()
221 {
222 return this.moduleVendor;
223 }
224
225
226
227
228
229
230
231
232 public void setModuleVendor( final String value )
233 {
234 this.moduleVendor = value;
235 }
236
237
238
239
240
241
242
243
244
245
246
247 public Set<NameType> getModuleIncludes()
248 {
249 if ( this.moduleIncludes == null )
250 {
251 this.moduleIncludes = new HashSet<NameType>();
252 }
253
254 return this.moduleIncludes;
255 }
256
257
258
259
260
261
262
263
264 public NameType createModuleInclude()
265 {
266 final NameType moduleInclude = new NameType();
267 this.getModuleIncludes().add( moduleInclude );
268 return moduleInclude;
269 }
270
271
272
273
274
275
276
277
278
279
280
281 public Set<NameType> getModuleExcludes()
282 {
283 if ( this.moduleExcludes == null )
284 {
285 this.moduleExcludes = new HashSet<NameType>();
286 }
287
288 return this.moduleExcludes;
289 }
290
291
292
293
294
295
296
297
298 public NameType createModuleExclude()
299 {
300 final NameType moduleExclude = new NameType();
301 this.getModuleExcludes().add( moduleExclude );
302 return moduleExclude;
303 }
304
305
306
307
308
309
310
311
312
313
314
315 public List<TransformerResourceType> getModelObjectStylesheetResources()
316 {
317 if ( this.modelObjectStylesheetResources == null )
318 {
319 this.modelObjectStylesheetResources = new LinkedList<TransformerResourceType>();
320 }
321
322 return this.modelObjectStylesheetResources;
323 }
324
325
326
327
328
329
330
331
332 public TransformerResourceType createModelObjectStylesheetResource()
333 {
334 final TransformerResourceType modelObjectStylesheetResource = new TransformerResourceType();
335 this.getModelObjectStylesheetResources().add( modelObjectStylesheetResource );
336 return modelObjectStylesheetResource;
337 }
338
339
340 @Override
341 public void preExecuteTask() throws BuildException
342 {
343 super.preExecuteTask();
344
345 this.assertNotNull( "moduleFile", this.getModuleFile() );
346 this.assertNotNull( "moduleName", this.getModuleName() );
347 this.assertNamesNotNull( this.getModuleExcludes() );
348 this.assertNamesNotNull( this.getModuleIncludes() );
349 this.assertLocationsNotNull( this.getModelObjectStylesheetResources() );
350 }
351
352
353
354
355
356
357 @Override
358 public void executeTask() throws BuildException
359 {
360 ProjectClassLoader classLoader = null;
361 boolean suppressExceptionOnClose = true;
362
363 try
364 {
365 this.log( Messages.getMessage( "mergingModules", this.getModel() ) );
366
367 classLoader = this.newProjectClassLoader();
368 final Modules modules = new Modules();
369 final Set<ResourceType> resources = new HashSet<ResourceType>( this.getModuleResources() );
370 final ModelContext context = this.newModelContext( classLoader );
371 final Marshaller marshaller = context.createMarshaller( this.getModel() );
372 final Unmarshaller unmarshaller = context.createUnmarshaller( this.getModel() );
373
374 if ( this.isModelResourceValidationEnabled() )
375 {
376 unmarshaller.setSchema( context.createSchema( this.getModel() ) );
377 }
378
379 if ( resources.isEmpty() )
380 {
381 final ResourceType defaultResource = new ResourceType();
382 defaultResource.setLocation( DefaultModelProvider.getDefaultModuleLocation() );
383 defaultResource.setOptional( true );
384 resources.add( defaultResource );
385 }
386
387 for ( ResourceType resource : resources )
388 {
389 final URL[] urls = this.getResources( context, resource.getLocation() );
390
391 if ( urls.length == 0 )
392 {
393 if ( resource.isOptional() )
394 {
395 this.logMessage( Level.WARNING, Messages.getMessage( "moduleResourceNotFound",
396 resource.getLocation() ) );
397
398 }
399 else
400 {
401 throw new BuildException(
402 Messages.getMessage( "moduleResourceNotFound", resource.getLocation() ),
403 this.getLocation() );
404
405 }
406 }
407
408 for ( int i = urls.length - 1; i >= 0; i-- )
409 {
410 InputStream in = null;
411 suppressExceptionOnClose = true;
412
413 try
414 {
415 this.logMessage( Level.FINEST, Messages.getMessage( "reading", urls[i].toExternalForm() ) );
416
417 final URLConnection con = urls[i].openConnection();
418 con.setConnectTimeout( resource.getConnectTimeout() );
419 con.setReadTimeout( resource.getReadTimeout() );
420 con.connect();
421 in = con.getInputStream();
422
423 final Source source = new StreamSource( in, urls[i].toURI().toASCIIString() );
424
425 Object o = unmarshaller.unmarshal( source );
426 if ( o instanceof JAXBElement<?> )
427 {
428 o = ( (JAXBElement<?>) o ).getValue();
429 }
430
431 if ( o instanceof Module )
432 {
433 modules.getModule().add( (Module) o );
434 }
435 else if ( o instanceof Modules )
436 {
437 modules.getModule().addAll( ( (Modules) o ).getModule() );
438 }
439 else
440 {
441 this.log( Messages.getMessage( "unsupportedModuleResource", urls[i].toExternalForm() ),
442 Project.MSG_WARN );
443
444 }
445
446 suppressExceptionOnClose = false;
447 }
448 catch ( final SocketTimeoutException e )
449 {
450 String message = Messages.getMessage( e );
451 message = Messages.getMessage( "resourceTimeout", message != null ? " " + message : "" );
452
453 if ( resource.isOptional() )
454 {
455 this.getProject().log( message, e, Project.MSG_WARN );
456 }
457 else
458 {
459 throw new BuildException( message, e, this.getLocation() );
460 }
461 }
462 catch ( final IOException e )
463 {
464 String message = Messages.getMessage( e );
465 message = Messages.getMessage( "resourceFailure", message != null ? " " + message : "" );
466
467 if ( resource.isOptional() )
468 {
469 this.getProject().log( message, e, Project.MSG_WARN );
470 }
471 else
472 {
473 throw new BuildException( message, e, this.getLocation() );
474 }
475 }
476 finally
477 {
478 try
479 {
480 if ( in != null )
481 {
482 in.close();
483 }
484 }
485 catch ( final IOException e )
486 {
487
488 if ( suppressExceptionOnClose )
489 {
490 this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
491 }
492 else
493 {
494 throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
495 }
496 }
497 }
498 }
499
500 suppressExceptionOnClose = true;
501 }
502
503 for ( final Iterator<Module> it = modules.getModule().iterator(); it.hasNext(); )
504 {
505 final Module module = it.next();
506
507 if ( !this.isModuleIncluded( module ) || this.isModuleExcluded( module ) )
508 {
509 it.remove();
510 this.log( Messages.getMessage( "excludingModule", module.getName() ) );
511 }
512 else
513 {
514 this.log( Messages.getMessage( "includingModule", module.getName() ) );
515 }
516 }
517
518 Module classpathModule = null;
519 if ( this.isModelObjectClasspathResolutionEnabled() )
520 {
521 classpathModule = modules.getClasspathModule( Modules.getDefaultClasspathModuleName(), classLoader );
522
523 if ( classpathModule != null && modules.getModule( Modules.getDefaultClasspathModuleName() ) == null )
524 {
525 modules.getModule().add( classpathModule );
526 }
527 else
528 {
529 classpathModule = null;
530 }
531 }
532
533 final ModelValidationReport validationReport = context.validateModel(
534 this.getModel(), new JAXBSource( marshaller, new ObjectFactory().createModules( modules ) ) );
535
536 this.logValidationReport( context, validationReport );
537
538 if ( !validationReport.isModelValid() )
539 {
540 throw new ModelException( Messages.getMessage( "invalidModel", this.getModel() ) );
541 }
542
543 if ( classpathModule != null )
544 {
545 modules.getModule().remove( classpathModule );
546 }
547
548 Module mergedModule = modules.getMergedModule( this.getModuleName() );
549 mergedModule.setVendor( this.getModuleVendor() );
550 mergedModule.setVersion( this.getModuleVersion() );
551
552 for ( int i = 0, s0 = this.getModelObjectStylesheetResources().size(); i < s0; i++ )
553 {
554 final Transformer transformer =
555 this.getTransformer( this.getModelObjectStylesheetResources().get( i ) );
556
557 if ( transformer != null )
558 {
559 final JAXBSource source =
560 new JAXBSource( marshaller, new ObjectFactory().createModule( mergedModule ) );
561
562 final JAXBResult result = new JAXBResult( unmarshaller );
563 transformer.transform( source, result );
564
565 if ( result.getResult() instanceof JAXBElement<?>
566 && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Module )
567 {
568 mergedModule = (Module) ( (JAXBElement<?>) result.getResult() ).getValue();
569 }
570 else
571 {
572 throw new BuildException( Messages.getMessage(
573 "illegalTransformationResult",
574 this.getModelObjectStylesheetResources().get( i ).getLocation() ), this.getLocation() );
575
576 }
577 }
578 }
579
580 this.log( Messages.getMessage( "writingEncoded", this.getModuleFile().getAbsolutePath(),
581 this.getModuleEncoding() ) );
582
583 marshaller.setProperty( Marshaller.JAXB_ENCODING, this.getModuleEncoding() );
584 marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
585 marshaller.setSchema( context.createSchema( this.getModel() ) );
586 marshaller.marshal( new ObjectFactory().createModule( mergedModule ), this.getModuleFile() );
587 suppressExceptionOnClose = false;
588 }
589 catch ( final URISyntaxException e )
590 {
591 throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
592 }
593 catch ( final JAXBException e )
594 {
595 String message = Messages.getMessage( e );
596 if ( message == null )
597 {
598 message = Messages.getMessage( e.getLinkedException() );
599 }
600
601 throw new BuildException( message, e, this.getLocation() );
602 }
603 catch ( final TransformerConfigurationException e )
604 {
605 throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
606 }
607 catch ( final TransformerException e )
608 {
609 throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
610 }
611 catch ( final ModelException e )
612 {
613 throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
614 }
615 finally
616 {
617 try
618 {
619 if ( classLoader != null )
620 {
621 classLoader.close();
622 }
623 }
624 catch ( final IOException e )
625 {
626 if ( suppressExceptionOnClose )
627 {
628 this.logMessage( Level.SEVERE, Messages.getMessage( e ), e );
629 }
630 else
631 {
632 throw new BuildException( Messages.getMessage( e ), e, this.getLocation() );
633 }
634 }
635 }
636 }
637
638
639
640
641
642
643
644
645
646
647
648
649 public boolean isModuleIncluded( final Module module )
650 {
651 if ( module == null )
652 {
653 throw new NullPointerException( "module" );
654 }
655
656 for ( NameType include : this.getModuleIncludes() )
657 {
658 if ( include.getName().equals( module.getName() ) )
659 {
660 return true;
661 }
662 }
663
664 return this.getModuleIncludes().isEmpty() ? true : false;
665 }
666
667
668
669
670
671
672
673
674
675
676
677
678 public boolean isModuleExcluded( final Module module )
679 {
680 if ( module == null )
681 {
682 throw new NullPointerException( "module" );
683 }
684
685 for ( NameType exclude : this.getModuleExcludes() )
686 {
687 if ( exclude.getName().equals( module.getName() ) )
688 {
689 return true;
690 }
691 }
692
693 return false;
694 }
695
696
697 @Override
698 public MergeModulesTask clone()
699 {
700 final MergeModulesTask clone = (MergeModulesTask) super.clone();
701 clone.moduleFile = this.moduleFile != null ? new File( this.moduleFile.getAbsolutePath() ) : null;
702
703 if ( this.moduleExcludes != null )
704 {
705 clone.moduleExcludes = new HashSet<NameType>( this.moduleExcludes.size() );
706 for ( NameType e : this.moduleExcludes )
707 {
708 clone.moduleExcludes.add( e.clone() );
709 }
710 }
711
712 if ( this.moduleIncludes != null )
713 {
714 clone.moduleIncludes = new HashSet<NameType>( this.moduleIncludes.size() );
715 for ( NameType e : this.moduleIncludes )
716 {
717 clone.moduleIncludes.add( e.clone() );
718 }
719 }
720
721 if ( this.modelObjectStylesheetResources != null )
722 {
723 clone.modelObjectStylesheetResources =
724 new ArrayList<TransformerResourceType>( this.modelObjectStylesheetResources.size() );
725
726 for ( TransformerResourceType e : this.modelObjectStylesheetResources )
727 {
728 clone.modelObjectStylesheetResources.add( e.clone() );
729 }
730 }
731
732 return clone;
733 }
734
735 }