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