001/* 002 * Copyright (C) Christian Schulte, 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: JomcResourceTransformer.java 4613 2012-09-22 10:07:08Z schulte $ 029 * 030 */ 031package org.jomc.mojo; 032 033import java.io.File; 034import java.io.IOException; 035import java.io.InputStream; 036import java.io.OutputStream; 037import java.net.MalformedURLException; 038import java.net.URISyntaxException; 039import java.net.URL; 040import java.util.Iterator; 041import java.util.List; 042import java.util.Map; 043import java.util.jar.JarEntry; 044import java.util.jar.JarOutputStream; 045import javax.xml.bind.JAXBElement; 046import javax.xml.bind.JAXBException; 047import javax.xml.bind.Marshaller; 048import javax.xml.bind.Unmarshaller; 049import javax.xml.bind.util.JAXBResult; 050import javax.xml.bind.util.JAXBSource; 051import javax.xml.transform.Transformer; 052import javax.xml.transform.TransformerConfigurationException; 053import javax.xml.transform.TransformerException; 054import javax.xml.transform.TransformerFactory; 055import javax.xml.transform.stream.StreamSource; 056import org.apache.maven.plugins.shade.resource.ResourceTransformer; 057import org.codehaus.plexus.logging.AbstractLogEnabled; 058import org.codehaus.plexus.util.StringUtils; 059import org.jomc.model.ModelObject; 060import org.jomc.model.Module; 061import org.jomc.model.Modules; 062import org.jomc.model.modlet.DefaultModelProvider; 063import org.jomc.modlet.DefaultModelContext; 064import org.jomc.modlet.DefaultModletProvider; 065import org.jomc.modlet.ModelContext; 066import org.jomc.modlet.ModelContextFactory; 067import org.jomc.modlet.ModelException; 068import org.jomc.modlet.Modlet; 069import org.jomc.modlet.ModletObject; 070import org.jomc.modlet.Modlets; 071 072/** 073 * Maven Shade Plugin {@code ResourceTransformer} implementation for shading JOMC resources. 074 * 075 * <p><b>Maven Shade Plugin Usage</b><pre> 076 * <transformer implementation="org.jomc.mojo.JomcResourceTransformer"> 077 * <model>http://jomc.org/model</model> 078 * <modelContextFactoryClassName>class name</modelContextFactoryClassName> 079 * <modelContextAttributes> 080 * <modelContextAttribute> 081 * <key>The name of the attribute</key> 082 * <value>The name of the attribute</value> 083 * <type>The name of the class of the object.</type> 084 * </modelContextAttribute> 085 * </modelContextAttributes/> 086 * <moduleEncoding>${project.build.sourceEncoding}</moduleEncoding> 087 * <moduleName>${project.name}</moduleName> 088 * <moduleVersion>${project.version}</moduleVersion> 089 * <moduleVendor>${project.organization.name}</moduleVendor> 090 * <moduleResource>META-INF/custom-jomc.xml</moduleResource> 091 * <moduleResources> 092 * <moduleResource>META-INF/jomc.xml</moduleResource> 093 * </moduleResources> 094 * <moduleIncludes> 095 * <moduleInclude>module name</moduleInclude> 096 * </moduleIncludes> 097 * <moduleExcludes> 098 * <moduleExclude>module name</moduleExclude> 099 * </moduleExcludes> 100 * <modletEncoding>${project.build.sourceEncoding}</modletEncoding> 101 * <modletName>${project.name}</modletName> 102 * <modletVersion>${project.version}</modletVersion> 103 * <modletVendor>${project.organization.name}</modletVendor> 104 * <modletResource>META-INF/custom-jomc-modlet.xml</modletResource> 105 * <modletResources> 106 * <modletResource>META-INF/jomc-modlet.xml</modletResource> 107 * </modletResources> 108 * <modletIncludes> 109 * <modletInclude>modlet name</modletInclude> 110 * </modletIncludes> 111 * <modletExcludes> 112 * <modletExclude>modlet name</modletExclude> 113 * </modletExcludes> 114 * <modelObjectStylesheet>Location of a XSLT document to use for transforming the merged model document.</modelObjectStylesheet> 115 * <modletObjectStylesheet>Location of a XSLT document to use for transforming the merged modlet document.</modletObjectStylesheet> 116 * <providerLocation>META-INF/custom-services</providerLocation> 117 * <platformProviderLocation>${java.home}/jre/lib/custom-jomc.properties</platformProviderLocation> 118 * <modletLocation>META-INF/custom-jomc-modlet.xml</modletLocation> 119 * <modletSchemaSystemId>http://custom.host.tld/custom/path/jomc-modlet-1.3.xsd</modletSchemaSystemId> 120 * </transformer> 121 * </pre></p> 122 * 123 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 124 * @version $JOMC: JomcResourceTransformer.java 4613 2012-09-22 10:07:08Z schulte $ 125 * @plexus.component role="org.apache.maven.plugins.shade.resource.ResourceTransformer" 126 * role-hint="JOMC" 127 */ 128public class JomcResourceTransformer extends AbstractLogEnabled implements ResourceTransformer 129{ 130 131 /** Type of a resource. */ 132 private enum ResourceType 133 { 134 135 /** Model object resource. */ 136 MODEL_OBJECT_RESOURCE, 137 /** Modlet object resource. */ 138 MODLET_OBJECT_RESOURCE 139 140 } 141 142 /** Prefix prepended to log messages. */ 143 private static final String LOG_PREFIX = "[JOMC] "; 144 145 /** The identifier of the model to process. */ 146 private String model = ModelObject.MODEL_PUBLIC_ID; 147 148 /** The encoding of the assembled module. */ 149 private String moduleEncoding; 150 151 /** The name of the assembled module. */ 152 private String moduleName; 153 154 /** The version of the assembled module. */ 155 private String moduleVersion; 156 157 /** The vendor of the assembled module. */ 158 private String moduleVendor; 159 160 /** The resource name of the assembled module. */ 161 private String moduleResource = DefaultModelProvider.getDefaultModuleLocation(); 162 163 /** Names of resources to process. */ 164 private String[] moduleResources = 165 { 166 DefaultModelProvider.getDefaultModuleLocation() 167 }; 168 169 /** Included modules. */ 170 private List<String> moduleIncludes; 171 172 /** Excluded modules. */ 173 private List<String> moduleExcludes; 174 175 /** The encoding of the assembled modlet. */ 176 private String modletEncoding; 177 178 /** The name of the assembled modlet. */ 179 private String modletName; 180 181 /** The version of the assembled modlet. */ 182 private String modletVersion; 183 184 /** The vendor of the assembled modlet. */ 185 private String modletVendor; 186 187 /** The resource name of the assembled modlet resources. */ 188 private String modletResource = DefaultModletProvider.getDefaultModletLocation(); 189 190 /** Names of modlet resources to process. */ 191 private String[] modletResources = 192 { 193 DefaultModletProvider.getDefaultModletLocation() 194 }; 195 196 /** Included modlets. */ 197 private List<String> modletIncludes; 198 199 /** Excluded modlets. */ 200 private List<String> modletExcludes; 201 202 /** Location of a XSLT document to use for transforming the merged model document. */ 203 private String modelObjectStylesheet; 204 205 /** Location of a XSLT document to use for transforming the merged modlet document. */ 206 private String modletObjectStylesheet; 207 208 /** The location to search for providers. */ 209 private String providerLocation; 210 211 /** The location to search for platform providers. */ 212 private String platformProviderLocation; 213 214 /** The system id of the modlet schema. */ 215 private String modletSchemaSystemId; 216 217 /** The location to search for modlets. */ 218 private String modletLocation; 219 220 /** 221 * Name of the {@code ModelContext} implementation class. 222 * @since 1.2 223 */ 224 private String modelContextFactoryClassName; 225 226 /** 227 * {@code ModelContext} attributes to apply. 228 * @since 1.2 229 */ 230 private List<ModelContextAttribute> modelContextAttributes; 231 232 /** Modlet resources. */ 233 private Modlets modlets = new Modlets(); 234 235 /** Model resources. */ 236 private Modules modules = new Modules(); 237 238 /** Type of the currently processed resource or {@code null}. */ 239 private ResourceType currentResourceType; 240 241 /** The JOMC JAXB marshaller of the instance. */ 242 private Marshaller jomcMarshaller; 243 244 /** The JOMC JAXB unmarshaller of the instance. */ 245 private Unmarshaller jomcUnmarshaller; 246 247 /** The modlet JAXB marshaller of the instance. */ 248 private Marshaller modletMarshaller; 249 250 /** The modlet JAXB unmarshaller of the instance. */ 251 private Unmarshaller modletUnmarshaller; 252 253 /** Creates a new {@code JomcResourceTransformer} instance. */ 254 public JomcResourceTransformer() 255 { 256 super(); 257 } 258 259 public boolean canTransformResource( final String arg ) 260 { 261 boolean transformable = false; 262 this.currentResourceType = null; 263 final String name = normalizeResourceName( arg ); 264 265 if ( name != null ) 266 { 267 if ( this.moduleResources != null ) 268 { 269 for ( String r : this.moduleResources ) 270 { 271 if ( name.equals( normalizeResourceName( r ) ) ) 272 { 273 this.currentResourceType = ResourceType.MODEL_OBJECT_RESOURCE; 274 275 if ( this.getLogger() != null && this.getLogger().isDebugEnabled() ) 276 { 277 this.getLogger().debug( LOG_PREFIX + Messages.getMessage( 278 "processingModuleResource", arg ) ); 279 280 } 281 282 transformable = true; 283 break; 284 } 285 } 286 } 287 288 if ( !transformable && this.modletResources != null ) 289 { 290 for ( String r : this.modletResources ) 291 { 292 if ( name.equals( normalizeResourceName( r ) ) ) 293 { 294 this.currentResourceType = ResourceType.MODLET_OBJECT_RESOURCE; 295 296 if ( this.getLogger() != null && this.getLogger().isDebugEnabled() ) 297 { 298 this.getLogger().debug( LOG_PREFIX + Messages.getMessage( 299 "processingModletResource", arg ) ); 300 301 } 302 303 transformable = true; 304 break; 305 } 306 } 307 } 308 309 if ( !transformable && ( name.equals( normalizeResourceName( this.modletResource ) ) 310 || name.equals( normalizeResourceName( this.moduleResource ) ) ) ) 311 { 312 if ( this.getLogger() != null && this.getLogger().isWarnEnabled() ) 313 { 314 this.getLogger().warn( LOG_PREFIX + Messages.getMessage( "overridingResource", arg ) ); 315 } 316 317 transformable = true; 318 this.currentResourceType = null; 319 } 320 } 321 322 return transformable; 323 } 324 325 public void processResource( final InputStream in ) throws IOException 326 { 327 try 328 { 329 if ( in != null && this.currentResourceType != null ) 330 { 331 switch ( this.currentResourceType ) 332 { 333 case MODEL_OBJECT_RESOURCE: 334 Object modelObject = this.unmarshalModelObject( in ); 335 336 if ( modelObject instanceof JAXBElement<?> ) 337 { 338 modelObject = ( (JAXBElement<?>) modelObject ).getValue(); 339 } 340 if ( modelObject instanceof Modules ) 341 { 342 this.modules.getModule().addAll( ( (Modules) modelObject ).getModule() ); 343 } 344 if ( modelObject instanceof Module ) 345 { 346 this.modules.getModule().add( (Module) modelObject ); 347 } 348 break; 349 350 case MODLET_OBJECT_RESOURCE: 351 Object modletObject = this.unmarshalModletObject( in ); 352 353 if ( modletObject instanceof JAXBElement<?> ) 354 { 355 modletObject = ( (JAXBElement<?>) modletObject ).getValue(); 356 } 357 if ( modletObject instanceof Modlets ) 358 { 359 this.modlets.getModlet().addAll( ( (Modlets) modletObject ).getModlet() ); 360 } 361 if ( modletObject instanceof Modlet ) 362 { 363 this.modlets.getModlet().add( (Modlet) modletObject ); 364 } 365 break; 366 367 default: 368 throw new AssertionError( this.currentResourceType ); 369 370 } 371 } 372 } 373 catch ( final InstantiationException e ) 374 { 375 // JDK: As of JDK 6, "new IOException( message, cause )". 376 throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e ); 377 } 378 catch ( final JAXBException e ) 379 { 380 String message = Messages.getMessage( e ); 381 if ( message == null && e.getLinkedException() != null ) 382 { 383 message = Messages.getMessage( e.getLinkedException() ); 384 } 385 386 // JDK: As of JDK 6, "new IOException( message, cause )". 387 throw (IOException) new IOException( message ).initCause( e ); 388 } 389 catch ( final ModelException e ) 390 { 391 // JDK: As of JDK 6, "new IOException( message, cause )". 392 throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e ); 393 } 394 } 395 396 public void processResource( final String name, final InputStream in, final List relocators ) throws IOException 397 { 398 this.processResource( in ); 399 } 400 401 public boolean hasTransformedResource() 402 { 403 return !( this.modules.getModule().isEmpty() && this.modlets.getModlet().isEmpty() ); 404 } 405 406 public void modifyOutputStream( final JarOutputStream out ) throws IOException 407 { 408 if ( StringUtils.isEmpty( this.model ) ) 409 { 410 throw new IOException( Messages.getMessage( "mandatoryParameter", "model" ) ); 411 } 412 if ( StringUtils.isEmpty( this.modletName ) ) 413 { 414 throw new IOException( Messages.getMessage( "mandatoryParameter", "modletName" ) ); 415 } 416 if ( StringUtils.isEmpty( this.modletResource ) ) 417 { 418 throw new IOException( Messages.getMessage( "mandatoryParameter", "modletResource" ) ); 419 } 420 if ( StringUtils.isEmpty( this.moduleName ) ) 421 { 422 throw new IOException( Messages.getMessage( "mandatoryParameter", "moduleName" ) ); 423 } 424 if ( StringUtils.isEmpty( this.moduleResource ) ) 425 { 426 throw new IOException( Messages.getMessage( "mandatoryParameter", "moduleResource" ) ); 427 } 428 429 try 430 { 431 if ( !this.modules.getModule().isEmpty() ) 432 { 433 if ( this.moduleIncludes != null ) 434 { 435 for ( final Iterator<Module> it = this.modules.getModule().iterator(); it.hasNext(); ) 436 { 437 final Module m = it.next(); 438 439 if ( !this.moduleIncludes.contains( m.getName() ) ) 440 { 441 it.remove(); 442 443 if ( this.getLogger() != null && this.getLogger().isInfoEnabled() ) 444 { 445 this.getLogger().info( LOG_PREFIX + Messages.getMessage( 446 "excludingModule", m.getName() ) ); 447 448 } 449 } 450 } 451 } 452 453 if ( this.moduleExcludes != null ) 454 { 455 for ( String exclude : this.moduleExcludes ) 456 { 457 final Module excluded = this.modules.getModule( exclude ); 458 459 if ( excluded != null ) 460 { 461 this.modules.getModule().remove( excluded ); 462 463 if ( this.getLogger() != null && this.getLogger().isInfoEnabled() ) 464 { 465 this.getLogger().info( LOG_PREFIX + Messages.getMessage( 466 "excludingModule", excluded.getName() ) ); 467 468 } 469 } 470 } 471 } 472 473 if ( this.getLogger() != null && this.getLogger().isInfoEnabled() ) 474 { 475 for ( Module m : this.modules.getModule() ) 476 { 477 this.getLogger().info( LOG_PREFIX + Messages.getMessage( "includingModule", m.getName() ) ); 478 } 479 } 480 481 final Module mergedModule = this.modules.getMergedModule( this.moduleName ); 482 mergedModule.setVersion( this.moduleVersion ); 483 mergedModule.setVendor( this.moduleVendor ); 484 485 final JAXBElement<Module> transformedModule = this.transformModelObject( 486 new org.jomc.model.ObjectFactory().createModule( mergedModule ), Module.class ); 487 488 out.putNextEntry( new JarEntry( normalizeResourceName( this.moduleResource ) ) ); 489 this.marshalModelObject( transformedModule, out ); 490 } 491 492 if ( !this.modlets.getModlet().isEmpty() ) 493 { 494 if ( this.modletIncludes != null ) 495 { 496 for ( final Iterator<Modlet> it = this.modlets.getModlet().iterator(); it.hasNext(); ) 497 { 498 final Modlet m = it.next(); 499 500 if ( !this.modletIncludes.contains( m.getName() ) ) 501 { 502 it.remove(); 503 504 if ( this.getLogger() != null && this.getLogger().isInfoEnabled() ) 505 { 506 this.getLogger().info( LOG_PREFIX + Messages.getMessage( 507 "excludingModlet", m.getName() ) ); 508 509 } 510 } 511 } 512 } 513 514 if ( this.modletExcludes != null ) 515 { 516 for ( String exclude : this.modletExcludes ) 517 { 518 final Modlet excluded = this.modlets.getModlet( exclude ); 519 520 if ( excluded != null ) 521 { 522 this.modlets.getModlet().remove( excluded ); 523 524 if ( this.getLogger() != null && this.getLogger().isInfoEnabled() ) 525 { 526 this.getLogger().info( LOG_PREFIX + Messages.getMessage( 527 "excludingModlet", excluded.getName() ) ); 528 529 } 530 } 531 } 532 } 533 534 if ( this.getLogger() != null && this.getLogger().isInfoEnabled() ) 535 { 536 for ( Modlet m : this.modlets.getModlet() ) 537 { 538 this.getLogger().info( LOG_PREFIX + Messages.getMessage( "includingModlet", m.getName() ) ); 539 } 540 } 541 542 final Modlet mergedModlet = this.modlets.getMergedModlet( this.modletName, this.model ); 543 mergedModlet.setVendor( this.modletVendor ); 544 mergedModlet.setVersion( this.modletVersion ); 545 546 final JAXBElement<Modlet> transformedModlet = this.transformModletObject( 547 new org.jomc.modlet.ObjectFactory().createModlet( mergedModlet ), Modlet.class ); 548 549 out.putNextEntry( new JarEntry( normalizeResourceName( this.modletResource ) ) ); 550 this.marshalModletObject( transformedModlet, out ); 551 } 552 } 553 catch ( final InstantiationException e ) 554 { 555 // JDK: As of JDK 6, "new IOException( message, cause )". 556 throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e ); 557 } 558 catch ( final TransformerConfigurationException e ) 559 { 560 String message = Messages.getMessage( e ); 561 if ( message == null && e.getException() != null ) 562 { 563 message = Messages.getMessage( e.getException() ); 564 } 565 566 // JDK: As of JDK 6, "new IOException( message, cause )". 567 throw (IOException) new IOException( message ).initCause( e ); 568 } 569 catch ( final TransformerException e ) 570 { 571 String message = Messages.getMessage( e ); 572 if ( message == null && e.getException() != null ) 573 { 574 message = Messages.getMessage( e.getException() ); 575 } 576 577 // JDK: As of JDK 6, "new IOException( message, cause )". 578 throw (IOException) new IOException( message ).initCause( e ); 579 } 580 catch ( final JAXBException e ) 581 { 582 String message = Messages.getMessage( e ); 583 if ( message == null && e.getLinkedException() != null ) 584 { 585 message = Messages.getMessage( e.getLinkedException() ); 586 } 587 588 // JDK: As of JDK 6, "new IOException( message, cause )". 589 throw (IOException) new IOException( message ).initCause( e ); 590 } 591 catch ( final ModelException e ) 592 { 593 // JDK: As of JDK 6, "new IOException( message, cause )". 594 throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e ); 595 } 596 catch ( final URISyntaxException e ) 597 { 598 // JDK: As of JDK 6, "new IOException( message, cause )". 599 throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e ); 600 } 601 finally 602 { 603 this.modlets = new Modlets(); 604 this.modules = new Modules(); 605 this.jomcMarshaller = null; 606 this.jomcUnmarshaller = null; 607 this.modletMarshaller = null; 608 this.modletUnmarshaller = null; 609 } 610 } 611 612 /** 613 * Creates an {@code URL} for a given resource location. 614 * <p>This method first searches the class loader of the class for a single resource matching {@code location}. If 615 * such a resource is found, the URL of that resource is returned. If no such resource is found, an attempt is made 616 * to parse the given location to an URL. On successful parsing, that URL is returned. Failing that, the given 617 * location is interpreted as a file name. If that file is found, the URL of that file is returned. Otherwise an 618 * {@code IOException} is thrown.</p> 619 * 620 * @param location The location to create an {@code URL} from. 621 * 622 * @return An {@code URL} for {@code location}. 623 * 624 * @throws NullPointerException if {@code location} is {@code null}. 625 * @throws IOException if creating an URL fails. 626 * 627 * @since 1.2 628 */ 629 protected URL getResource( final String location ) throws IOException 630 { 631 if ( location == null ) 632 { 633 throw new NullPointerException( "location" ); 634 } 635 636 try 637 { 638 String absolute = location; 639 if ( !absolute.startsWith( "/" ) ) 640 { 641 absolute = "/" + location; 642 } 643 644 URL resource = this.getClass().getResource( absolute ); 645 if ( resource == null ) 646 { 647 try 648 { 649 resource = new URL( location ); 650 } 651 catch ( final MalformedURLException e ) 652 { 653 if ( this.getLogger() != null && this.getLogger().isDebugEnabled() ) 654 { 655 this.getLogger().debug( Messages.getMessage( e ), e ); 656 } 657 658 resource = null; 659 } 660 } 661 662 if ( resource == null ) 663 { 664 final File f = new File( location ); 665 666 if ( f.isFile() ) 667 { 668 resource = f.toURI().toURL(); 669 } 670 } 671 672 if ( resource == null ) 673 { 674 throw new IOException( Messages.getMessage( "resourceNotFound", location ) ); 675 } 676 677 return resource; 678 } 679 catch ( final MalformedURLException e ) 680 { 681 String m = Messages.getMessage( e ); 682 m = m == null ? "" : " " + m; 683 684 // JDK: As of JDK 6, "new IOException( message, cause )". 685 throw (IOException) new IOException( Messages.getMessage( 686 "malformedLocation", location, m ) ).initCause( e ); 687 688 } 689 } 690 691 private Object unmarshalModelObject( final InputStream in ) 692 throws ModelException, JAXBException, InstantiationException 693 { 694 if ( in == null ) 695 { 696 throw new NullPointerException( "in" ); 697 } 698 699 if ( this.jomcUnmarshaller == null ) 700 { 701 this.jomcUnmarshaller = this.createModelContext().createUnmarshaller( this.model ); 702 } 703 704 return this.jomcUnmarshaller.unmarshal( in ); 705 } 706 707 private void marshalModelObject( final JAXBElement<? extends ModelObject> element, final OutputStream out ) 708 throws ModelException, JAXBException, InstantiationException 709 { 710 if ( element == null ) 711 { 712 throw new NullPointerException( "element" ); 713 } 714 if ( out == null ) 715 { 716 throw new NullPointerException( "out" ); 717 } 718 719 if ( this.jomcMarshaller == null ) 720 { 721 final ModelContext modelContext = this.createModelContext(); 722 this.jomcMarshaller = modelContext.createMarshaller( this.model ); 723 this.jomcMarshaller.setSchema( modelContext.createSchema( this.model ) ); 724 this.jomcMarshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE ); 725 726 if ( this.moduleEncoding != null ) 727 { 728 this.jomcMarshaller.setProperty( Marshaller.JAXB_ENCODING, this.moduleEncoding ); 729 } 730 } 731 732 this.jomcMarshaller.marshal( element, out ); 733 } 734 735 private <T> JAXBElement<T> transformModelObject( final JAXBElement<? extends ModelObject> element, 736 final Class<T> boundType ) 737 throws ModelException, TransformerException, JAXBException, IOException, URISyntaxException, 738 InstantiationException 739 { 740 if ( element == null ) 741 { 742 throw new NullPointerException( "element" ); 743 } 744 if ( !boundType.isInstance( element.getValue() ) ) 745 { 746 throw new IllegalArgumentException( element.toString() ); 747 } 748 749 @SuppressWarnings( "unchecked" ) 750 JAXBElement<T> transformed = (JAXBElement<T>) element; 751 752 if ( this.modelObjectStylesheet != null ) 753 { 754 final Transformer transformer = TransformerFactory.newInstance().newTransformer( 755 new StreamSource( this.getResource( this.modelObjectStylesheet ).toURI().toASCIIString() ) ); 756 757 final ModelContext modelContext = this.createModelContext(); 758 final Marshaller marshaller = modelContext.createMarshaller( this.model ); 759 final Unmarshaller unmarshaller = modelContext.createUnmarshaller( this.model ); 760 final JAXBSource source = new JAXBSource( marshaller, element ); 761 final JAXBResult result = new JAXBResult( unmarshaller ); 762 763 for ( Map.Entry<Object, Object> e : System.getProperties().entrySet() ) 764 { 765 transformer.setParameter( e.getKey().toString(), e.getValue() ); 766 } 767 768 transformer.transform( source, result ); 769 770 if ( result.getResult() instanceof JAXBElement<?> 771 && boundType.isInstance( ( (JAXBElement<?>) result.getResult() ).getValue() ) ) 772 { 773 @SuppressWarnings( "unchecked" ) final JAXBElement<T> e = (JAXBElement<T>) result.getResult(); 774 transformed = e; 775 } 776 else 777 { 778 throw new ModelException( Messages.getMessage( 779 "illegalModuleTransformationResult", this.modelObjectStylesheet ) ); 780 781 } 782 } 783 784 return transformed; 785 } 786 787 private Object unmarshalModletObject( final InputStream in ) 788 throws ModelException, JAXBException, InstantiationException 789 { 790 if ( in == null ) 791 { 792 throw new NullPointerException( "in" ); 793 } 794 795 if ( this.modletUnmarshaller == null ) 796 { 797 this.modletUnmarshaller = this.createModelContext().createUnmarshaller( ModletObject.MODEL_PUBLIC_ID ); 798 } 799 800 return this.modletUnmarshaller.unmarshal( in ); 801 } 802 803 private void marshalModletObject( final JAXBElement<? extends ModletObject> element, final OutputStream out ) 804 throws ModelException, JAXBException, InstantiationException 805 { 806 if ( element == null ) 807 { 808 throw new NullPointerException( "element" ); 809 } 810 if ( out == null ) 811 { 812 throw new NullPointerException( "out" ); 813 } 814 815 if ( this.modletMarshaller == null ) 816 { 817 final ModelContext modletContext = this.createModelContext(); 818 this.modletMarshaller = modletContext.createMarshaller( ModletObject.MODEL_PUBLIC_ID ); 819 this.modletMarshaller.setSchema( modletContext.createSchema( ModletObject.MODEL_PUBLIC_ID ) ); 820 this.modletMarshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE ); 821 822 if ( this.modletEncoding != null ) 823 { 824 this.modletMarshaller.setProperty( Marshaller.JAXB_ENCODING, this.modletEncoding ); 825 } 826 } 827 828 this.modletMarshaller.marshal( element, out ); 829 } 830 831 private <T> JAXBElement<T> transformModletObject( final JAXBElement<? extends ModletObject> element, 832 final Class<T> boundType ) 833 throws ModelException, TransformerException, JAXBException, IOException, URISyntaxException, 834 InstantiationException 835 { 836 if ( element == null ) 837 { 838 throw new NullPointerException( "element" ); 839 } 840 if ( !boundType.isInstance( element.getValue() ) ) 841 { 842 throw new IllegalArgumentException( element.toString() ); 843 } 844 845 @SuppressWarnings( "unchecked" ) 846 JAXBElement<T> transformed = (JAXBElement<T>) element; 847 848 if ( this.modletObjectStylesheet != null ) 849 { 850 final Transformer transformer = TransformerFactory.newInstance().newTransformer( 851 new StreamSource( this.getResource( this.modletObjectStylesheet ).toURI().toASCIIString() ) ); 852 853 final ModelContext modletContext = this.createModelContext(); 854 final Marshaller marshaller = modletContext.createMarshaller( ModletObject.MODEL_PUBLIC_ID ); 855 final Unmarshaller unmarshaller = modletContext.createUnmarshaller( ModletObject.MODEL_PUBLIC_ID ); 856 final JAXBSource source = new JAXBSource( marshaller, element ); 857 final JAXBResult result = new JAXBResult( unmarshaller ); 858 859 for ( Map.Entry<Object, Object> e : System.getProperties().entrySet() ) 860 { 861 transformer.setParameter( e.getKey().toString(), e.getValue() ); 862 } 863 864 transformer.transform( source, result ); 865 866 if ( result.getResult() instanceof JAXBElement<?> 867 && boundType.isInstance( ( (JAXBElement<?>) result.getResult() ).getValue() ) ) 868 { 869 @SuppressWarnings( "unchecked" ) final JAXBElement<T> e = (JAXBElement<T>) result.getResult(); 870 transformed = e; 871 } 872 else 873 { 874 throw new ModelException( Messages.getMessage( 875 "illegalModletTransformationResult", this.modletObjectStylesheet ) ); 876 877 } 878 } 879 880 return transformed; 881 } 882 883 private static String normalizeResourceName( final String name ) 884 { 885 String normalized = name; 886 887 if ( normalized != null ) 888 { 889 normalized = normalized.replace( '\\', '/' ); 890 891 if ( normalized.startsWith( "/" ) ) 892 { 893 normalized = normalized.substring( 1 ); 894 } 895 896 if ( normalized.endsWith( "/" ) ) 897 { 898 normalized = normalized.substring( 0, normalized.length() ); 899 } 900 } 901 902 return normalized; 903 } 904 905 private ModelContext createModelContext() throws ModelException, InstantiationException 906 { 907 final ModelContextFactory modelContextFactory; 908 if ( this.modelContextFactoryClassName != null ) 909 { 910 modelContextFactory = ModelContextFactory.newInstance( this.modelContextFactoryClassName ); 911 } 912 else 913 { 914 modelContextFactory = ModelContextFactory.newInstance(); 915 } 916 917 final ModelContext modelContext = modelContextFactory.newModelContext(); 918 modelContext.setModletSchemaSystemId( this.modletSchemaSystemId ); 919 920 if ( this.providerLocation != null ) 921 { 922 modelContext.setAttribute( DefaultModelContext.PROVIDER_LOCATION_ATTRIBUTE_NAME, this.providerLocation ); 923 } 924 925 if ( this.platformProviderLocation != null ) 926 { 927 modelContext.setAttribute( DefaultModelContext.PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME, 928 this.platformProviderLocation ); 929 930 } 931 932 if ( this.modletLocation != null ) 933 { 934 modelContext.setAttribute( DefaultModletProvider.MODLET_LOCATION_ATTRIBUTE_NAME, this.modletLocation ); 935 } 936 937 if ( this.modelContextAttributes != null ) 938 { 939 for ( ModelContextAttribute e : this.modelContextAttributes ) 940 { 941 final Object object = e.getObject(); 942 943 if ( object != null ) 944 { 945 modelContext.setAttribute( e.getKey(), object ); 946 } 947 else 948 { 949 modelContext.clearAttribute( e.getKey() ); 950 } 951 } 952 } 953 954 return modelContext; 955 } 956 957}