001/* 002 * Copyright (C) Christian Schulte <cs@schulte.it>, 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: DefaultModelContext.java 5051 2015-05-30 17:29:32Z schulte $ 029 * 030 */ 031package org.jomc.modlet; 032 033import java.io.BufferedReader; 034import java.io.File; 035import java.io.FileInputStream; 036import java.io.IOException; 037import java.io.InputStream; 038import java.io.InputStreamReader; 039import java.io.Reader; 040import java.net.URI; 041import java.net.URISyntaxException; 042import java.net.URL; 043import java.text.MessageFormat; 044import java.util.ArrayList; 045import java.util.Collection; 046import java.util.Collections; 047import java.util.Comparator; 048import java.util.Enumeration; 049import java.util.HashSet; 050import java.util.List; 051import java.util.Map; 052import java.util.ResourceBundle; 053import java.util.Set; 054import java.util.StringTokenizer; 055import java.util.TreeMap; 056import java.util.jar.Attributes; 057import java.util.jar.Manifest; 058import java.util.logging.Level; 059import javax.xml.XMLConstants; 060import javax.xml.bind.JAXBContext; 061import javax.xml.bind.JAXBException; 062import javax.xml.bind.Marshaller; 063import javax.xml.bind.Unmarshaller; 064import javax.xml.transform.Source; 065import javax.xml.transform.sax.SAXSource; 066import javax.xml.validation.SchemaFactory; 067import javax.xml.validation.Validator; 068import org.w3c.dom.ls.LSInput; 069import org.w3c.dom.ls.LSResourceResolver; 070import org.xml.sax.EntityResolver; 071import org.xml.sax.ErrorHandler; 072import org.xml.sax.InputSource; 073import org.xml.sax.SAXException; 074import org.xml.sax.SAXParseException; 075import org.xml.sax.helpers.DefaultHandler; 076 077/** 078 * Default {@code ModelContext} implementation. 079 * 080 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 081 * @version $JOMC: DefaultModelContext.java 5051 2015-05-30 17:29:32Z schulte $ 082 * @see ModelContextFactory 083 */ 084public class DefaultModelContext extends ModelContext 085{ 086 087 /** 088 * Constant for the name of the model context attribute backing property {@code providerLocation}. 089 * 090 * @see #getProviderLocation() 091 * @see ModelContext#getAttribute(java.lang.String) 092 * @since 1.2 093 */ 094 public static final String PROVIDER_LOCATION_ATTRIBUTE_NAME = 095 "org.jomc.modlet.DefaultModelContext.providerLocationAttribute"; 096 097 /** 098 * Constant for the name of the model context attribute backing property {@code platformProviderLocation}. 099 * 100 * @see #getPlatformProviderLocation() 101 * @see ModelContext#getAttribute(java.lang.String) 102 * @since 1.2 103 */ 104 public static final String PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME = 105 "org.jomc.modlet.DefaultModelContext.platformProviderLocationAttribute"; 106 107 /** 108 * Supported schema name extensions. 109 */ 110 private static final String[] SCHEMA_EXTENSIONS = new String[] 111 { 112 "xsd" 113 }; 114 115 /** 116 * Class path location searched for providers by default. 117 * 118 * @see #getDefaultProviderLocation() 119 */ 120 private static final String DEFAULT_PROVIDER_LOCATION = "META-INF/services"; 121 122 /** 123 * Location searched for platform providers by default. 124 * 125 * @see #getDefaultPlatformProviderLocation() 126 */ 127 private static final String DEFAULT_PLATFORM_PROVIDER_LOCATION = 128 new StringBuilder( 255 ).append( System.getProperty( "java.home" ) ).append( File.separator ).append( "lib" ). 129 append( File.separator ).append( "jomc.properties" ).toString(); 130 131 /** 132 * Constant for the service identifier of marshaller listener services. 133 * 134 * @since 1.2 135 */ 136 private static final String MARSHALLER_LISTENER_SERVICE = "javax.xml.bind.Marshaller.Listener"; 137 138 /** 139 * Constant for the service identifier of unmarshaller listener services. 140 * 141 * @since 1.2 142 */ 143 private static final String UNMARSHALLER_LISTENER_SERVICE = "javax.xml.bind.Unmarshaller.Listener"; 144 145 /** 146 * Default provider location. 147 */ 148 private static volatile String defaultProviderLocation; 149 150 /** 151 * Default platform provider location. 152 */ 153 private static volatile String defaultPlatformProviderLocation; 154 155 /** 156 * Provider location of the instance. 157 */ 158 private String providerLocation; 159 160 /** 161 * Platform provider location of the instance. 162 */ 163 private String platformProviderLocation; 164 165 /** 166 * Creates a new {@code DefaultModelContext} instance. 167 * 168 * @since 1.2 169 */ 170 public DefaultModelContext() 171 { 172 super(); 173 } 174 175 /** 176 * Creates a new {@code DefaultModelContext} instance taking a class loader. 177 * 178 * @param classLoader The class loader of the context. 179 */ 180 public DefaultModelContext( final ClassLoader classLoader ) 181 { 182 super( classLoader ); 183 } 184 185 /** 186 * Gets the default location searched for provider resources. 187 * <p> 188 * The default provider location is controlled by system property 189 * {@code org.jomc.modlet.DefaultModelContext.defaultProviderLocation} holding the location to search 190 * for provider resources by default. If that property is not set, the {@code META-INF/services} default is 191 * returned. 192 * </p> 193 * 194 * @return The location searched for provider resources by default. 195 * 196 * @see #setDefaultProviderLocation(java.lang.String) 197 */ 198 public static String getDefaultProviderLocation() 199 { 200 if ( defaultProviderLocation == null ) 201 { 202 defaultProviderLocation = System.getProperty( 203 "org.jomc.modlet.DefaultModelContext.defaultProviderLocation", DEFAULT_PROVIDER_LOCATION ); 204 205 } 206 207 return defaultProviderLocation; 208 } 209 210 /** 211 * Sets the default location searched for provider resources. 212 * 213 * @param value The new default location to search for provider resources or {@code null}. 214 * 215 * @see #getDefaultProviderLocation() 216 */ 217 public static void setDefaultProviderLocation( final String value ) 218 { 219 defaultProviderLocation = value; 220 } 221 222 /** 223 * Gets the location searched for provider resources. 224 * 225 * @return The location searched for provider resources. 226 * 227 * @see #getDefaultProviderLocation() 228 * @see #setProviderLocation(java.lang.String) 229 * @see #PROVIDER_LOCATION_ATTRIBUTE_NAME 230 */ 231 public final String getProviderLocation() 232 { 233 if ( this.providerLocation == null ) 234 { 235 this.providerLocation = getDefaultProviderLocation(); 236 237 if ( DEFAULT_PROVIDER_LOCATION.equals( this.providerLocation ) 238 && this.getAttribute( PROVIDER_LOCATION_ATTRIBUTE_NAME ) instanceof String ) 239 { 240 final String contextProviderLocation = (String) this.getAttribute( PROVIDER_LOCATION_ATTRIBUTE_NAME ); 241 242 if ( this.isLoggable( Level.CONFIG ) ) 243 { 244 this.log( Level.CONFIG, getMessage( "contextProviderLocationInfo", 245 contextProviderLocation ), null ); 246 } 247 248 this.providerLocation = null; 249 return contextProviderLocation; 250 } 251 else if ( this.isLoggable( Level.CONFIG ) ) 252 { 253 this.log( Level.CONFIG, getMessage( "defaultProviderLocationInfo", this.providerLocation ), null ); 254 } 255 } 256 257 return this.providerLocation; 258 } 259 260 /** 261 * Sets the location searched for provider resources. 262 * 263 * @param value The new location to search for provider resources or {@code null}. 264 * 265 * @see #getProviderLocation() 266 */ 267 public final void setProviderLocation( final String value ) 268 { 269 this.providerLocation = value; 270 } 271 272 /** 273 * Gets the default location searched for platform provider resources. 274 * <p> 275 * The default platform provider location is controlled by system property 276 * {@code org.jomc.modlet.DefaultModelContext.defaultPlatformProviderLocation} holding the location to 277 * search for platform provider resources by default. If that property is not set, the 278 * {@code <java-home>/lib/jomc.properties} default is returned. 279 * </p> 280 * 281 * @return The location searched for platform provider resources by default. 282 * 283 * @see #setDefaultPlatformProviderLocation(java.lang.String) 284 */ 285 public static String getDefaultPlatformProviderLocation() 286 { 287 if ( defaultPlatformProviderLocation == null ) 288 { 289 defaultPlatformProviderLocation = System.getProperty( 290 "org.jomc.modlet.DefaultModelContext.defaultPlatformProviderLocation", 291 DEFAULT_PLATFORM_PROVIDER_LOCATION ); 292 293 } 294 295 return defaultPlatformProviderLocation; 296 } 297 298 /** 299 * Sets the default location searched for platform provider resources. 300 * 301 * @param value The new default location to search for platform provider resources or {@code null}. 302 * 303 * @see #getDefaultPlatformProviderLocation() 304 */ 305 public static void setDefaultPlatformProviderLocation( final String value ) 306 { 307 defaultPlatformProviderLocation = value; 308 } 309 310 /** 311 * Gets the location searched for platform provider resources. 312 * 313 * @return The location searched for platform provider resources. 314 * 315 * @see #getDefaultPlatformProviderLocation() 316 * @see #setPlatformProviderLocation(java.lang.String) 317 * @see #PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME 318 */ 319 public final String getPlatformProviderLocation() 320 { 321 if ( this.platformProviderLocation == null ) 322 { 323 this.platformProviderLocation = getDefaultPlatformProviderLocation(); 324 325 if ( DEFAULT_PLATFORM_PROVIDER_LOCATION.equals( this.platformProviderLocation ) 326 && this.getAttribute( PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME ) instanceof String ) 327 { 328 final String contextPlatformProviderLocation = 329 (String) this.getAttribute( PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME ); 330 331 if ( this.isLoggable( Level.CONFIG ) ) 332 { 333 this.log( Level.CONFIG, getMessage( "contextPlatformProviderLocationInfo", 334 contextPlatformProviderLocation ), null ); 335 336 } 337 338 this.platformProviderLocation = null; 339 return contextPlatformProviderLocation; 340 } 341 else if ( this.isLoggable( Level.CONFIG ) ) 342 { 343 this.log( Level.CONFIG, 344 getMessage( "defaultPlatformProviderLocationInfo", this.platformProviderLocation ), null ); 345 346 } 347 } 348 349 return this.platformProviderLocation; 350 } 351 352 /** 353 * Sets the location searched for platform provider resources. 354 * 355 * @param value The new location to search for platform provider resources or {@code null}. 356 * 357 * @see #getPlatformProviderLocation() 358 */ 359 public final void setPlatformProviderLocation( final String value ) 360 { 361 this.platformProviderLocation = value; 362 } 363 364 /** 365 * {@inheritDoc} 366 * <p> 367 * This method loads {@code ModletProvider} classes setup via the platform provider configuration file and 368 * {@code <provider-location>/org.jomc.modlet.ModletProvider} resources to return a list of {@code Modlets}. 369 * </p> 370 * 371 * @see #getProviderLocation() 372 * @see #getPlatformProviderLocation() 373 * @see ModletProvider#findModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets) 374 * @deprecated As of JOMC 1.6, replaced by {@link #findModlets(org.jomc.modlet.Modlets)}. This method will be 375 * removed in JOMC 2.0. 376 */ 377 @Override 378 @Deprecated 379 public Modlets findModlets() throws ModelException 380 { 381 return this.findModlets( new Modlets() ); 382 } 383 384 /** 385 * {@inheritDoc} 386 * <p> 387 * This method loads {@code ModletProvider} classes setup via the platform provider configuration file and 388 * {@code <provider-location>/org.jomc.modlet.ModletProvider} resources to return a list of {@code Modlets}. 389 * </p> 390 * 391 * @see #getProviderLocation() 392 * @see #getPlatformProviderLocation() 393 * @see ModletProvider#findModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets) 394 * @since 1.6 395 */ 396 @Override 397 public Modlets findModlets( final Modlets modlets ) throws ModelException 398 { 399 if ( modlets == null ) 400 { 401 throw new NullPointerException( "modlets" ); 402 } 403 404 Modlets found = modlets.clone(); 405 final Collection<ModletProvider> providers = this.loadModletServices( ModletProvider.class ); 406 407 for ( final ModletProvider provider : providers ) 408 { 409 if ( this.isLoggable( Level.FINER ) ) 410 { 411 this.log( Level.FINER, getMessage( "creatingModlets", provider.toString() ), null ); 412 } 413 414 final Modlets provided = provider.findModlets( this, found ); 415 416 if ( provided != null ) 417 { 418 found = provided; 419 } 420 } 421 422 if ( this.isLoggable( Level.FINEST ) ) 423 { 424 for ( final Modlet m : found.getModlet() ) 425 { 426 this.log( Level.FINEST, 427 getMessage( "modletInfo", m.getName(), m.getModel(), 428 m.getVendor() != null 429 ? m.getVendor() : getMessage( "noVendor" ), 430 m.getVersion() != null 431 ? m.getVersion() : getMessage( "noVersion" ) ), null ); 432 433 if ( m.getSchemas() != null ) 434 { 435 for ( final Schema s : m.getSchemas().getSchema() ) 436 { 437 this.log( Level.FINEST, 438 getMessage( "modletSchemaInfo", m.getName(), s.getPublicId(), s.getSystemId(), 439 s.getContextId() != null 440 ? s.getContextId() : getMessage( "noContext" ), 441 s.getClasspathId() != null 442 ? s.getClasspathId() : getMessage( "noClasspathId" ) ), null ); 443 444 } 445 } 446 447 if ( m.getServices() != null ) 448 { 449 for ( final Service s : m.getServices().getService() ) 450 { 451 this.log( Level.FINEST, getMessage( "modletServiceInfo", m.getName(), s.getOrdinal(), 452 s.getIdentifier(), s.getClazz() ), null ); 453 454 } 455 } 456 } 457 } 458 459 return found; 460 } 461 462 /** 463 * {@inheritDoc} 464 * <p> 465 * This method loads {@code ModletProcessor} classes setup via the platform provider configuration file and 466 * {@code <provider-location>/org.jomc.modlet.ModletProcessor} resources to process a list of {@code Modlets}. 467 * </p> 468 * 469 * @see #getProviderLocation() 470 * @see #getPlatformProviderLocation() 471 * @see ModletProcessor#processModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets) 472 * @since 1.6 473 */ 474 @Override 475 public Modlets processModlets( final Modlets modlets ) throws ModelException 476 { 477 if ( modlets == null ) 478 { 479 throw new NullPointerException( "modlets" ); 480 } 481 482 Modlets result = modlets.clone(); 483 final Collection<ModletProcessor> processors = this.loadModletServices( ModletProcessor.class ); 484 485 for ( final ModletProcessor processor : processors ) 486 { 487 if ( this.isLoggable( Level.FINER ) ) 488 { 489 this.log( Level.FINER, getMessage( "processingModlets", processor.toString() ), null ); 490 } 491 492 final Modlets processed = processor.processModlets( this, result ); 493 494 if ( processed != null ) 495 { 496 result = processed; 497 } 498 } 499 500 return result; 501 } 502 503 /** 504 * {@inheritDoc} 505 * <p> 506 * This method loads {@code ModletValidator} classes setup via the platform provider configuration file and 507 * {@code <provider-location>/org.jomc.modlet.ModletValidator} resources to validate a list of {@code Modlets}. 508 * </p> 509 * 510 * @see #getProviderLocation() 511 * @see #getPlatformProviderLocation() 512 * @see ModletValidator#validateModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets) 513 * @since 1.9 514 */ 515 @Override 516 public ModelValidationReport validateModlets( final Modlets modlets ) throws ModelException 517 { 518 if ( modlets == null ) 519 { 520 throw new NullPointerException( "modlets" ); 521 } 522 523 final ModelValidationReport report = new ModelValidationReport(); 524 final Collection<ModletValidator> modletValidators = this.loadModletServices( ModletValidator.class ); 525 526 for ( final ModletValidator modletValidator : modletValidators ) 527 { 528 if ( this.isLoggable( Level.FINER ) ) 529 { 530 this.log( Level.FINER, getMessage( "validatingModlets", modletValidator.toString() ), null ); 531 } 532 533 final ModelValidationReport current = modletValidator.validateModlets( this, modlets ); 534 535 if ( current != null ) 536 { 537 report.getDetails().addAll( current.getDetails() ); 538 } 539 } 540 541 return report; 542 } 543 544 /** 545 * {@inheritDoc} 546 * <p> 547 * This method creates all {@code ModelProvider} service objects of the model identified by {@code model} to create 548 * a new {@code Model} instance. 549 * </p> 550 * 551 * @see #findModel(org.jomc.modlet.Model) 552 * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProvider.class.getName(), ModelProvider.class ) 553 * @see ModelProvider#findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model) 554 */ 555 @Override 556 public Model findModel( final String model ) throws ModelException 557 { 558 if ( model == null ) 559 { 560 throw new NullPointerException( "model" ); 561 } 562 563 final Model m = new Model(); 564 m.setIdentifier( model ); 565 566 return this.findModel( m ); 567 } 568 569 /** 570 * {@inheritDoc} 571 * <p> 572 * This method creates all {@code ModelProvider} service objects of the given model to populate the given model 573 * instance. 574 * </p> 575 * 576 * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProvider.class.getName(), ModelProvider.class ) 577 * @see ModelProvider#findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model) 578 * 579 * @since 1.2 580 */ 581 @Override 582 public Model findModel( final Model model ) throws ModelException 583 { 584 if ( model == null ) 585 { 586 throw new NullPointerException( "model" ); 587 } 588 589 Model m = model.clone(); 590 final long t0 = System.currentTimeMillis(); 591 592 for ( final ModelProvider provider 593 : this.createServiceObjects( model.getIdentifier(), ModelProvider.class.getName(), 594 ModelProvider.class ) ) 595 { 596 if ( this.isLoggable( Level.FINER ) ) 597 { 598 this.log( Level.FINER, getMessage( "creatingModel", m.getIdentifier(), provider.toString() ), null ); 599 } 600 601 final Model provided = provider.findModel( this, m ); 602 603 if ( provided != null ) 604 { 605 m = provided; 606 } 607 } 608 609 if ( this.isLoggable( Level.FINE ) ) 610 { 611 this.log( Level.FINE, getMessage( "findModelReport", m.getIdentifier(), System.currentTimeMillis() - t0 ), 612 null ); 613 614 } 615 616 return m; 617 } 618 619 /** 620 * {@inheritDoc} 621 * <p> 622 * This method creates all {@code ModelProcessor} service objects of {@code model} to process the given 623 * {@code Model}. 624 * </p> 625 * 626 * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProcessor.class.getName(), ModelProcessor.class ) 627 * @see ModelProcessor#processModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model) 628 */ 629 @Override 630 public Model processModel( final Model model ) throws ModelException 631 { 632 if ( model == null ) 633 { 634 throw new NullPointerException( "model" ); 635 } 636 637 Model processed = model; 638 final long t0 = System.currentTimeMillis(); 639 640 for ( final ModelProcessor processor 641 : this.createServiceObjects( model.getIdentifier(), ModelProcessor.class.getName(), 642 ModelProcessor.class ) ) 643 { 644 if ( this.isLoggable( Level.FINER ) ) 645 { 646 this.log( Level.FINER, getMessage( "processingModel", model.getIdentifier(), 647 processor.toString() ), null ); 648 649 } 650 651 final Model current = processor.processModel( this, processed ); 652 653 if ( current != null ) 654 { 655 processed = current; 656 } 657 } 658 659 if ( this.isLoggable( Level.FINE ) ) 660 { 661 this.log( Level.FINE, getMessage( "processModelReport", model.getIdentifier(), 662 System.currentTimeMillis() - t0 ), null ); 663 664 } 665 666 return processed; 667 } 668 669 /** 670 * {@inheritDoc} 671 * <p> 672 * This method creates all {@code ModelValidator} service objects of {@code model} to validate the given 673 * {@code Model}. 674 * </p> 675 * 676 * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelValidator.class.getName(), ModelValidator.class ) 677 * @see ModelValidator#validateModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model) 678 */ 679 @Override 680 public ModelValidationReport validateModel( final Model model ) throws ModelException 681 { 682 if ( model == null ) 683 { 684 throw new NullPointerException( "model" ); 685 } 686 687 final long t0 = System.currentTimeMillis(); 688 final ModelValidationReport report = new ModelValidationReport(); 689 690 for ( final ModelValidator validator 691 : this.createServiceObjects( model.getIdentifier(), ModelValidator.class.getName(), 692 ModelValidator.class ) ) 693 { 694 if ( this.isLoggable( Level.FINER ) ) 695 { 696 this.log( Level.FINER, getMessage( "validatingModel", model.getIdentifier(), 697 validator.toString() ), null ); 698 699 } 700 701 final ModelValidationReport current = validator.validateModel( this, model ); 702 703 if ( current != null ) 704 { 705 report.getDetails().addAll( current.getDetails() ); 706 } 707 } 708 709 if ( this.isLoggable( Level.FINE ) ) 710 { 711 this.log( Level.FINE, getMessage( "validateModelReport", model.getIdentifier(), 712 System.currentTimeMillis() - t0 ), null ); 713 714 } 715 716 return report; 717 } 718 719 /** 720 * {@inheritDoc} 721 * 722 * @see #createSchema(java.lang.String) 723 */ 724 @Override 725 public ModelValidationReport validateModel( final String model, final Source source ) throws ModelException 726 { 727 if ( model == null ) 728 { 729 throw new NullPointerException( "model" ); 730 } 731 if ( source == null ) 732 { 733 throw new NullPointerException( "source" ); 734 } 735 736 final long t0 = System.currentTimeMillis(); 737 final javax.xml.validation.Schema schema = this.createSchema( model ); 738 final Validator validator = schema.newValidator(); 739 final ModelErrorHandler modelErrorHandler = new ModelErrorHandler( this ); 740 validator.setErrorHandler( modelErrorHandler ); 741 742 try 743 { 744 validator.validate( source ); 745 } 746 catch ( final SAXException e ) 747 { 748 String message = getMessage( e ); 749 if ( message == null && e.getException() != null ) 750 { 751 message = getMessage( e.getException() ); 752 } 753 754 if ( this.isLoggable( Level.FINE ) ) 755 { 756 this.log( Level.FINE, message, e ); 757 } 758 759 if ( modelErrorHandler.getReport().isModelValid() ) 760 { 761 throw new ModelException( message, e ); 762 } 763 } 764 catch ( final IOException e ) 765 { 766 throw new ModelException( getMessage( e ), e ); 767 } 768 769 if ( this.isLoggable( Level.FINE ) ) 770 { 771 this.log( Level.FINE, getMessage( "validateModelReport", model, System.currentTimeMillis() - t0 ), null ); 772 } 773 774 return modelErrorHandler.getReport(); 775 } 776 777 @Override 778 public EntityResolver createEntityResolver( final String model ) throws ModelException 779 { 780 if ( model == null ) 781 { 782 throw new NullPointerException( "model" ); 783 } 784 785 return this.createEntityResolver( this.getModlets().getSchemas( model ) ); 786 } 787 788 @Override 789 @Deprecated 790 public EntityResolver createEntityResolver( final URI publicId ) throws ModelException 791 { 792 if ( publicId == null ) 793 { 794 throw new NullPointerException( "publicId" ); 795 } 796 797 return this.createEntityResolver( this.getModlets().getSchemas( publicId ) ); 798 } 799 800 @Override 801 public LSResourceResolver createResourceResolver( final String model ) throws ModelException 802 { 803 if ( model == null ) 804 { 805 throw new NullPointerException( "model" ); 806 } 807 808 return this.createResourceResolver( this.createEntityResolver( model ) ); 809 } 810 811 @Override 812 @Deprecated 813 public LSResourceResolver createResourceResolver( final URI publicId ) throws ModelException 814 { 815 if ( publicId == null ) 816 { 817 throw new NullPointerException( "publicId" ); 818 } 819 820 return this.createResourceResolver( this.createEntityResolver( publicId ) ); 821 } 822 823 @Override 824 public javax.xml.validation.Schema createSchema( final String model ) throws ModelException 825 { 826 if ( model == null ) 827 { 828 throw new NullPointerException( "model" ); 829 } 830 831 return this.createSchema( this.getModlets().getSchemas( model ), this.createEntityResolver( model ), 832 this.createResourceResolver( model ), model, null ); 833 834 } 835 836 @Override 837 @Deprecated 838 public javax.xml.validation.Schema createSchema( final URI publicId ) throws ModelException 839 { 840 if ( publicId == null ) 841 { 842 throw new NullPointerException( "publicId" ); 843 } 844 845 return this.createSchema( this.getModlets().getSchemas( publicId ), this.createEntityResolver( publicId ), 846 this.createResourceResolver( publicId ), null, publicId ); 847 848 } 849 850 @Override 851 public JAXBContext createContext( final String model ) throws ModelException 852 { 853 if ( model == null ) 854 { 855 throw new NullPointerException( "model" ); 856 } 857 858 return this.createContext( this.getModlets().getSchemas( model ), model, null ); 859 } 860 861 @Override 862 @Deprecated 863 public JAXBContext createContext( final URI publicId ) throws ModelException 864 { 865 if ( publicId == null ) 866 { 867 throw new NullPointerException( "publicId" ); 868 } 869 870 return this.createContext( this.getModlets().getSchemas( publicId ), null, publicId ); 871 } 872 873 @Override 874 public Marshaller createMarshaller( final String model ) throws ModelException 875 { 876 if ( model == null ) 877 { 878 throw new NullPointerException( "model" ); 879 } 880 881 return this.createMarshaller( model, null ); 882 } 883 884 @Override 885 @Deprecated 886 public Marshaller createMarshaller( final URI publicId ) throws ModelException 887 { 888 if ( publicId == null ) 889 { 890 throw new NullPointerException( "publicId" ); 891 } 892 893 return this.createMarshaller( null, publicId ); 894 } 895 896 @Override 897 public Unmarshaller createUnmarshaller( final String model ) throws ModelException 898 { 899 if ( model == null ) 900 { 901 throw new NullPointerException( "model" ); 902 } 903 904 return this.createUnmarshaller( model, null ); 905 } 906 907 @Override 908 @Deprecated 909 public Unmarshaller createUnmarshaller( final URI publicId ) throws ModelException 910 { 911 if ( publicId == null ) 912 { 913 throw new NullPointerException( "publicId" ); 914 } 915 916 return this.createUnmarshaller( null, publicId ); 917 } 918 919 /** 920 * {@inheritDoc} 921 * <p> 922 * This method loads {@code ServiceFactory} classes setup via the platform provider configuration file and 923 * {@code <provider-location>/org.jomc.modlet.ServiceFactory} resources to create a new service object. 924 * </p> 925 * 926 * @since 1.9 927 */ 928 @Override 929 public <T> Collection<? extends T> createServiceObjects( final String model, final String service, 930 final Class<T> type ) 931 throws ModelException 932 { 933 if ( model == null ) 934 { 935 throw new NullPointerException( "model" ); 936 } 937 if ( service == null ) 938 { 939 throw new NullPointerException( "service" ); 940 } 941 if ( type == null ) 942 { 943 throw new NullPointerException( "type" ); 944 } 945 946 final Services modelServices = this.getModlets().getServices( model ); 947 final Collection<T> serviceObjects = 948 new ArrayList<T>( modelServices != null ? modelServices.getService().size() : 0 ); 949 950 if ( modelServices != null ) 951 { 952 final Collection<ServiceFactory> factories = this.loadModletServices( ServiceFactory.class ); 953 954 for ( final Service s : modelServices.getServices( service ) ) 955 { 956 serviceObjects.add( this.createServiceObject( s, type, factories ) ); 957 } 958 } 959 960 return Collections.unmodifiableCollection( serviceObjects ); 961 } 962 963 /** 964 * {@inheritDoc} 965 * <p> 966 * This method loads {@code ServiceFactory} classes setup via the platform provider configuration file and 967 * {@code <provider-location>/org.jomc.modlet.ServiceFactory} resources to create a new service object. 968 * </p> 969 * 970 * @see #getProviderLocation() 971 * @see #getPlatformProviderLocation() 972 * @see ServiceFactory#createServiceObject(org.jomc.modlet.ModelContext, org.jomc.modlet.Service, java.lang.Class) 973 * @since 1.2 974 * @deprecated As of JOMC 1.9, please use method {@link #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class)}. 975 * This method will be removed in JOMC 2.0. 976 */ 977 @Override 978 @Deprecated 979 public <T> T createServiceObject( final Service service, final Class<T> type ) throws ModelException 980 { 981 if ( service == null ) 982 { 983 throw new NullPointerException( "service" ); 984 } 985 if ( type == null ) 986 { 987 throw new NullPointerException( "type" ); 988 } 989 990 return this.createServiceObject( service, type, this.loadModletServices( ServiceFactory.class ) ); 991 } 992 993 /** 994 * This method creates a new service object for a given service using a given collection of service factories. 995 * 996 * @param <T> The type of the service. 997 * @param service The service to create a new object of. 998 * @param type The class of the type of the service. 999 * @param factories The service factories to use for creating the new service object. 1000 * 1001 * @return An new service object for {@code service}. 1002 * 1003 * @throws NullPointerException if {@code service}, {@code type} or {@code factories} is {@code null}. 1004 * @throws ModelException if creating the service object fails. 1005 * @since 1.9 1006 */ 1007 private <T> T createServiceObject( final Service service, final Class<T> type, 1008 final Collection<ServiceFactory> factories ) throws ModelException 1009 { 1010 if ( service == null ) 1011 { 1012 throw new NullPointerException( "service" ); 1013 } 1014 if ( type == null ) 1015 { 1016 throw new NullPointerException( "type" ); 1017 } 1018 if ( factories == null ) 1019 { 1020 throw new NullPointerException( "factories" ); 1021 } 1022 1023 T serviceObject = null; 1024 1025 for ( final ServiceFactory factory : factories ) 1026 { 1027 final T current = factory.createServiceObject( this, service, type ); 1028 1029 if ( current != null ) 1030 { 1031 if ( this.isLoggable( Level.FINER ) ) 1032 { 1033 this.log( Level.FINER, getMessage( "creatingService", service.getOrdinal(), service.getIdentifier(), 1034 service.getClazz(), factory.toString() ), null ); 1035 1036 } 1037 1038 serviceObject = current; 1039 break; 1040 } 1041 } 1042 1043 if ( serviceObject == null ) 1044 { 1045 throw new ModelException( getMessage( "serviceNotCreated", service.getOrdinal(), service.getIdentifier(), 1046 service.getClazz() ), null ); 1047 1048 } 1049 1050 return serviceObject; 1051 } 1052 1053 private <T> Collection<T> loadModletServices( final Class<T> serviceClass ) throws ModelException 1054 { 1055 try 1056 { 1057 final String serviceNamePrefix = serviceClass.getName() + "."; 1058 final Map<String, T> sortedPlatformServices = new TreeMap<String, T>( new Comparator<String>() 1059 { 1060 1061 public int compare( final String key1, final String key2 ) 1062 { 1063 return key1.compareTo( key2 ); 1064 } 1065 1066 } ); 1067 1068 final File platformServices = new File( this.getPlatformProviderLocation() ); 1069 1070 if ( platformServices.exists() ) 1071 { 1072 if ( this.isLoggable( Level.FINEST ) ) 1073 { 1074 this.log( Level.FINEST, getMessage( "processing", platformServices.getAbsolutePath() ), null ); 1075 } 1076 1077 InputStream in = null; 1078 boolean suppressExceptionOnClose = true; 1079 final java.util.Properties p = new java.util.Properties(); 1080 1081 try 1082 { 1083 in = new FileInputStream( platformServices ); 1084 p.load( in ); 1085 suppressExceptionOnClose = false; 1086 } 1087 finally 1088 { 1089 try 1090 { 1091 if ( in != null ) 1092 { 1093 in.close(); 1094 } 1095 } 1096 catch ( final IOException e ) 1097 { 1098 if ( suppressExceptionOnClose ) 1099 { 1100 this.log( Level.SEVERE, getMessage( e ), e ); 1101 } 1102 else 1103 { 1104 throw e; 1105 } 1106 } 1107 } 1108 1109 for ( final Map.Entry<Object, Object> e : p.entrySet() ) 1110 { 1111 if ( e.getKey().toString().startsWith( serviceNamePrefix ) ) 1112 { 1113 final String configuration = e.getValue().toString(); 1114 1115 if ( this.isLoggable( Level.FINEST ) ) 1116 { 1117 this.log( Level.FINEST, getMessage( "serviceInfo", platformServices.getAbsolutePath(), 1118 serviceClass.getName(), configuration ), null ); 1119 1120 } 1121 1122 sortedPlatformServices.put( e.getKey().toString(), 1123 this.createModletServiceObject( serviceClass, configuration ) ); 1124 1125 } 1126 } 1127 } 1128 1129 final Enumeration<URL> classpathServices = 1130 this.findResources( this.getProviderLocation() + '/' + serviceClass.getName() ); 1131 1132 int count = 0; 1133 final long t0 = System.currentTimeMillis(); 1134 final List<T> sortedClasspathServices = new ArrayList<T>(); 1135 1136 while ( classpathServices.hasMoreElements() ) 1137 { 1138 count++; 1139 final URL url = classpathServices.nextElement(); 1140 1141 if ( this.isLoggable( Level.FINEST ) ) 1142 { 1143 this.log( Level.FINEST, getMessage( "processing", url.toExternalForm() ), null ); 1144 } 1145 1146 BufferedReader reader = null; 1147 boolean suppressExceptionOnClose = true; 1148 1149 try 1150 { 1151 reader = new BufferedReader( new InputStreamReader( url.openStream(), "UTF-8" ) ); 1152 1153 String line; 1154 while ( ( line = reader.readLine() ) != null ) 1155 { 1156 if ( line.contains( "#" ) ) 1157 { 1158 continue; 1159 } 1160 1161 if ( this.isLoggable( Level.FINEST ) ) 1162 { 1163 this.log( Level.FINEST, getMessage( "serviceInfo", url.toExternalForm(), 1164 serviceClass.getName(), line ), null ); 1165 1166 } 1167 1168 final T serviceObject = this.createModletServiceObject( serviceClass, line ); 1169 sortedClasspathServices.add( serviceObject ); 1170 } 1171 1172 Collections.sort( sortedClasspathServices, 1173 new Comparator<Object>() 1174 { 1175 1176 public int compare( final Object o1, final Object o2 ) 1177 { 1178 return ordinalOf( o1 ) - ordinalOf( o2 ); 1179 } 1180 1181 } ); 1182 1183 suppressExceptionOnClose = false; 1184 } 1185 finally 1186 { 1187 try 1188 { 1189 if ( reader != null ) 1190 { 1191 reader.close(); 1192 } 1193 } 1194 catch ( final IOException e ) 1195 { 1196 if ( suppressExceptionOnClose ) 1197 { 1198 this.log( Level.SEVERE, getMessage( e ), e ); 1199 } 1200 else 1201 { 1202 throw new ModelException( getMessage( e ), e ); 1203 } 1204 } 1205 } 1206 } 1207 1208 if ( this.isLoggable( Level.FINE ) ) 1209 { 1210 this.log( Level.FINE, getMessage( "contextReport", count, 1211 this.getProviderLocation() + '/' + serviceClass.getName(), 1212 System.currentTimeMillis() - t0 ), null ); 1213 1214 } 1215 1216 final List<T> services = 1217 new ArrayList<T>( sortedPlatformServices.size() + sortedClasspathServices.size() ); 1218 1219 services.addAll( sortedPlatformServices.values() ); 1220 services.addAll( sortedClasspathServices ); 1221 1222 return services; 1223 } 1224 catch ( final IOException e ) 1225 { 1226 throw new ModelException( getMessage( e ), e ); 1227 } 1228 } 1229 1230 private <T> T createModletServiceObject( final Class<T> serviceClass, final String configuration ) 1231 throws ModelException 1232 { 1233 String className = configuration; 1234 final int i0 = configuration.indexOf( '[' ); 1235 final int i1 = configuration.lastIndexOf( ']' ); 1236 final Service service = new Service(); 1237 service.setIdentifier( serviceClass.getName() ); 1238 1239 if ( i0 != -1 && i1 != -1 ) 1240 { 1241 className = configuration.substring( 0, i0 ); 1242 final StringTokenizer propertyTokens = 1243 new StringTokenizer( configuration.substring( i0 + 1, i1 ), "," ); 1244 1245 while ( propertyTokens.hasMoreTokens() ) 1246 { 1247 final String property = propertyTokens.nextToken(); 1248 final int d0 = property.indexOf( '=' ); 1249 1250 String propertyName = property; 1251 String propertyValue = null; 1252 1253 if ( d0 != -1 ) 1254 { 1255 propertyName = property.substring( 0, d0 ); 1256 propertyValue = property.substring( d0 + 1, property.length() ); 1257 } 1258 1259 final Property p = new Property(); 1260 service.getProperty().add( p ); 1261 1262 p.setName( propertyName ); 1263 p.setValue( propertyValue ); 1264 } 1265 } 1266 1267 service.setClazz( className ); 1268 1269 // Need a way to exchange the service factory creating modlet service objects? 1270 return new DefaultServiceFactory().createServiceObject( this, service, serviceClass ); 1271 } 1272 1273 /** 1274 * Searches the context for {@code META-INF/MANIFEST.MF} resources and returns a set of URIs of entries whose names 1275 * end with a known schema extension. 1276 * 1277 * @return Set of URIs of any matching entries. 1278 * 1279 * @throws IOException if reading fails. 1280 * @throws URISyntaxException if parsing fails. 1281 * @throws ModelException if searching the context fails. 1282 */ 1283 private Set<URI> getSchemaResources() throws IOException, URISyntaxException, ModelException 1284 { 1285 final Set<URI> resources = new HashSet<URI>(); 1286 final long t0 = System.currentTimeMillis(); 1287 int count = 0; 1288 1289 for ( final Enumeration<URL> e = this.findResources( "META-INF/MANIFEST.MF" ); 1290 e.hasMoreElements(); ) 1291 { 1292 InputStream manifestStream = null; 1293 boolean suppressExceptionOnClose = true; 1294 1295 try 1296 { 1297 count++; 1298 final URL manifestUrl = e.nextElement(); 1299 final String externalForm = manifestUrl.toExternalForm(); 1300 final String baseUrl = externalForm.substring( 0, externalForm.indexOf( "META-INF" ) ); 1301 manifestStream = manifestUrl.openStream(); 1302 final Manifest mf = new Manifest( manifestStream ); 1303 1304 if ( this.isLoggable( Level.FINEST ) ) 1305 { 1306 this.log( Level.FINEST, getMessage( "processing", externalForm ), null ); 1307 } 1308 1309 for ( final Map.Entry<String, Attributes> entry : mf.getEntries().entrySet() ) 1310 { 1311 for ( int i = SCHEMA_EXTENSIONS.length - 1; i >= 0; i-- ) 1312 { 1313 if ( entry.getKey().toLowerCase().endsWith( '.' + SCHEMA_EXTENSIONS[i].toLowerCase() ) ) 1314 { 1315 final URL schemaUrl = new URL( baseUrl + entry.getKey() ); 1316 resources.add( schemaUrl.toURI() ); 1317 1318 if ( this.isLoggable( Level.FINEST ) ) 1319 { 1320 this.log( Level.FINEST, getMessage( "foundSchemaCandidate", 1321 schemaUrl.toExternalForm() ), null ); 1322 1323 } 1324 } 1325 } 1326 } 1327 1328 suppressExceptionOnClose = false; 1329 } 1330 finally 1331 { 1332 try 1333 { 1334 if ( manifestStream != null ) 1335 { 1336 manifestStream.close(); 1337 } 1338 } 1339 catch ( final IOException ex ) 1340 { 1341 if ( suppressExceptionOnClose ) 1342 { 1343 this.log( Level.SEVERE, getMessage( ex ), ex ); 1344 } 1345 else 1346 { 1347 throw ex; 1348 } 1349 } 1350 } 1351 } 1352 1353 if ( this.isLoggable( Level.FINE ) ) 1354 { 1355 this.log( Level.FINE, getMessage( "contextReport", count, "META-INF/MANIFEST.MF", 1356 System.currentTimeMillis() - t0 ), null ); 1357 1358 } 1359 1360 return resources; 1361 } 1362 1363 private EntityResolver createEntityResolver( final Schemas schemas ) 1364 { 1365 return new DefaultHandler() 1366 { 1367 1368 @Override 1369 public InputSource resolveEntity( final String publicId, final String systemId ) 1370 throws SAXException, IOException 1371 { 1372 InputSource schemaSource = null; 1373 1374 try 1375 { 1376 Schema s = null; 1377 1378 if ( schemas != null ) 1379 { 1380 if ( systemId != null && !"".equals( systemId ) ) 1381 { 1382 s = schemas.getSchemaBySystemId( systemId ); 1383 } 1384 else if ( publicId != null ) 1385 { 1386 s = schemas.getSchemaByPublicId( publicId ); 1387 } 1388 } 1389 1390 if ( s != null ) 1391 { 1392 schemaSource = new InputSource(); 1393 schemaSource.setPublicId( s.getPublicId() ); 1394 schemaSource.setSystemId( s.getSystemId() ); 1395 1396 if ( s.getClasspathId() != null ) 1397 { 1398 final URL resource = findResource( s.getClasspathId() ); 1399 1400 if ( resource != null ) 1401 { 1402 schemaSource.setSystemId( resource.toExternalForm() ); 1403 } 1404 else if ( isLoggable( Level.WARNING ) ) 1405 { 1406 log( Level.WARNING, getMessage( "resourceNotFound", s.getClasspathId() ), null ); 1407 } 1408 } 1409 1410 if ( isLoggable( Level.FINEST ) ) 1411 { 1412 log( Level.FINEST, getMessage( "resolutionInfo", publicId + ", " + systemId, 1413 schemaSource.getPublicId() + ", " 1414 + schemaSource.getSystemId() ), null ); 1415 1416 } 1417 } 1418 1419 if ( schemaSource == null && systemId != null && !"".equals( systemId ) ) 1420 { 1421 final URI systemUri = new URI( systemId ); 1422 String schemaName = systemUri.getPath(); 1423 1424 if ( schemaName != null ) 1425 { 1426 final int lastIndexOfSlash = schemaName.lastIndexOf( '/' ); 1427 if ( lastIndexOfSlash != -1 && lastIndexOfSlash < schemaName.length() ) 1428 { 1429 schemaName = schemaName.substring( lastIndexOfSlash + 1 ); 1430 } 1431 1432 for ( final URI uri : getSchemaResources() ) 1433 { 1434 if ( uri.getSchemeSpecificPart() != null 1435 && uri.getSchemeSpecificPart().endsWith( schemaName ) ) 1436 { 1437 schemaSource = new InputSource(); 1438 schemaSource.setPublicId( publicId ); 1439 schemaSource.setSystemId( uri.toASCIIString() ); 1440 1441 if ( isLoggable( Level.FINEST ) ) 1442 { 1443 log( Level.FINEST, getMessage( "resolutionInfo", systemUri.toASCIIString(), 1444 schemaSource.getSystemId() ), null ); 1445 1446 } 1447 1448 break; 1449 } 1450 } 1451 } 1452 else 1453 { 1454 if ( isLoggable( Level.WARNING ) ) 1455 { 1456 log( Level.WARNING, getMessage( "unsupportedIdUri", systemId, 1457 systemUri.toASCIIString() ), null ); 1458 1459 } 1460 1461 schemaSource = null; 1462 } 1463 } 1464 } 1465 catch ( final URISyntaxException e ) 1466 { 1467 if ( isLoggable( Level.WARNING ) ) 1468 { 1469 log( Level.WARNING, getMessage( "unsupportedIdUri", systemId, getMessage( e ) ), null ); 1470 } 1471 1472 schemaSource = null; 1473 } 1474 catch ( final ModelException e ) 1475 { 1476 String message = getMessage( e ); 1477 if ( message == null ) 1478 { 1479 message = ""; 1480 } 1481 else if ( message.length() > 0 ) 1482 { 1483 message = " " + message; 1484 } 1485 1486 String resource = ""; 1487 if ( publicId != null ) 1488 { 1489 resource = publicId + ", "; 1490 } 1491 resource += systemId; 1492 1493 // JDK: As of JDK 6, "new IOException( message, cause )". 1494 throw (IOException) new IOException( getMessage( 1495 "failedResolving", resource, message ) ).initCause( e ); 1496 1497 } 1498 1499 return schemaSource; 1500 } 1501 1502 }; 1503 } 1504 1505 private LSResourceResolver createResourceResolver( final EntityResolver entityResolver ) 1506 { 1507 if ( entityResolver == null ) 1508 { 1509 throw new NullPointerException( "entityResolver" ); 1510 } 1511 1512 return new LSResourceResolver() 1513 { 1514 1515 public LSInput resolveResource( final String type, final String namespaceURI, final String publicId, 1516 final String systemId, final String baseURI ) 1517 { 1518 final String resolvePublicId = namespaceURI == null ? publicId : namespaceURI; 1519 final String resolveSystemId = systemId == null ? "" : systemId; 1520 1521 try 1522 { 1523 if ( XMLConstants.W3C_XML_SCHEMA_NS_URI.equals( type ) ) 1524 { 1525 final InputSource schemaSource = 1526 entityResolver.resolveEntity( resolvePublicId, resolveSystemId ); 1527 1528 if ( schemaSource != null ) 1529 { 1530 return new LSInput() 1531 { 1532 1533 public Reader getCharacterStream() 1534 { 1535 return schemaSource.getCharacterStream(); 1536 } 1537 1538 public void setCharacterStream( final Reader characterStream ) 1539 { 1540 if ( isLoggable( Level.WARNING ) ) 1541 { 1542 log( Level.WARNING, getMessage( 1543 "unsupportedOperation", "setCharacterStream", 1544 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null ); 1545 1546 } 1547 } 1548 1549 public InputStream getByteStream() 1550 { 1551 return schemaSource.getByteStream(); 1552 } 1553 1554 public void setByteStream( final InputStream byteStream ) 1555 { 1556 if ( isLoggable( Level.WARNING ) ) 1557 { 1558 log( Level.WARNING, getMessage( 1559 "unsupportedOperation", "setByteStream", 1560 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null ); 1561 1562 } 1563 } 1564 1565 public String getStringData() 1566 { 1567 return null; 1568 } 1569 1570 public void setStringData( final String stringData ) 1571 { 1572 if ( isLoggable( Level.WARNING ) ) 1573 { 1574 log( Level.WARNING, getMessage( 1575 "unsupportedOperation", "setStringData", 1576 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null ); 1577 1578 } 1579 } 1580 1581 public String getSystemId() 1582 { 1583 return schemaSource.getSystemId(); 1584 } 1585 1586 public void setSystemId( final String systemId ) 1587 { 1588 if ( isLoggable( Level.WARNING ) ) 1589 { 1590 log( Level.WARNING, getMessage( 1591 "unsupportedOperation", "setSystemId", 1592 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null ); 1593 1594 } 1595 } 1596 1597 public String getPublicId() 1598 { 1599 return schemaSource.getPublicId(); 1600 } 1601 1602 public void setPublicId( final String publicId ) 1603 { 1604 if ( isLoggable( Level.WARNING ) ) 1605 { 1606 log( Level.WARNING, getMessage( 1607 "unsupportedOperation", "setPublicId", 1608 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null ); 1609 1610 } 1611 } 1612 1613 public String getBaseURI() 1614 { 1615 return baseURI; 1616 } 1617 1618 public void setBaseURI( final String baseURI ) 1619 { 1620 if ( isLoggable( Level.WARNING ) ) 1621 { 1622 log( Level.WARNING, getMessage( 1623 "unsupportedOperation", "setBaseURI", 1624 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null ); 1625 1626 } 1627 } 1628 1629 public String getEncoding() 1630 { 1631 return schemaSource.getEncoding(); 1632 } 1633 1634 public void setEncoding( final String encoding ) 1635 { 1636 if ( isLoggable( Level.WARNING ) ) 1637 { 1638 log( Level.WARNING, getMessage( 1639 "unsupportedOperation", "setEncoding", 1640 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null ); 1641 1642 } 1643 } 1644 1645 public boolean getCertifiedText() 1646 { 1647 return false; 1648 } 1649 1650 public void setCertifiedText( final boolean certifiedText ) 1651 { 1652 if ( isLoggable( Level.WARNING ) ) 1653 { 1654 log( Level.WARNING, getMessage( 1655 "unsupportedOperation", "setCertifiedText", 1656 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null ); 1657 1658 } 1659 } 1660 1661 }; 1662 } 1663 1664 } 1665 else if ( isLoggable( Level.WARNING ) ) 1666 { 1667 log( Level.WARNING, getMessage( "unsupportedResourceType", type ), null ); 1668 } 1669 } 1670 catch ( final SAXException e ) 1671 { 1672 String message = getMessage( e ); 1673 if ( message == null && e.getException() != null ) 1674 { 1675 message = getMessage( e.getException() ); 1676 } 1677 if ( message == null ) 1678 { 1679 message = ""; 1680 } 1681 else if ( message.length() > 0 ) 1682 { 1683 message = " " + message; 1684 } 1685 1686 String resource = ""; 1687 if ( resolvePublicId != null ) 1688 { 1689 resource = resolvePublicId + ", "; 1690 } 1691 resource += resolveSystemId; 1692 1693 if ( isLoggable( Level.SEVERE ) ) 1694 { 1695 log( Level.SEVERE, getMessage( "failedResolving", resource, message ), e ); 1696 } 1697 } 1698 catch ( final IOException e ) 1699 { 1700 String message = getMessage( e ); 1701 if ( message == null ) 1702 { 1703 message = ""; 1704 } 1705 else if ( message.length() > 0 ) 1706 { 1707 message = " " + message; 1708 } 1709 1710 String resource = ""; 1711 if ( resolvePublicId != null ) 1712 { 1713 resource = resolvePublicId + ", "; 1714 } 1715 resource += resolveSystemId; 1716 1717 if ( isLoggable( Level.SEVERE ) ) 1718 { 1719 log( Level.SEVERE, getMessage( "failedResolving", resource, message ), e ); 1720 } 1721 } 1722 1723 return null; 1724 } 1725 1726 }; 1727 } 1728 1729 private javax.xml.validation.Schema createSchema( final Schemas schemas, final EntityResolver entityResolver, 1730 final LSResourceResolver resourceResolver, final String model, 1731 final URI publicId ) throws ModelException 1732 { 1733 if ( entityResolver == null ) 1734 { 1735 throw new NullPointerException( "entityResolver" ); 1736 } 1737 if ( model != null && publicId != null ) 1738 { 1739 throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() ); 1740 } 1741 1742 try 1743 { 1744 final long t0 = System.currentTimeMillis(); 1745 final SchemaFactory f = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI ); 1746 final List<Source> sources = new ArrayList<Source>( schemas != null ? schemas.getSchema().size() : 0 ); 1747 1748 if ( schemas != null ) 1749 { 1750 for ( final Schema s : schemas.getSchema() ) 1751 { 1752 final InputSource inputSource = entityResolver.resolveEntity( s.getPublicId(), s.getSystemId() ); 1753 1754 if ( inputSource != null ) 1755 { 1756 sources.add( new SAXSource( inputSource ) ); 1757 } 1758 } 1759 } 1760 1761 if ( sources.isEmpty() ) 1762 { 1763 if ( model != null ) 1764 { 1765 throw new ModelException( getMessage( "missingSchemasForModel", model ) ); 1766 } 1767 if ( publicId != null ) 1768 { 1769 throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) ); 1770 } 1771 } 1772 1773 f.setResourceResolver( resourceResolver ); 1774 f.setErrorHandler( new ErrorHandler() 1775 { 1776 // See http://java.net/jira/browse/JAXP-66 1777 1778 public void warning( final SAXParseException e ) throws SAXException 1779 { 1780 String message = getMessage( e ); 1781 if ( message == null && e.getException() != null ) 1782 { 1783 message = getMessage( e.getException() ); 1784 } 1785 1786 if ( isLoggable( Level.WARNING ) ) 1787 { 1788 log( Level.WARNING, message, e ); 1789 } 1790 } 1791 1792 public void error( final SAXParseException e ) throws SAXException 1793 { 1794 throw e; 1795 } 1796 1797 public void fatalError( final SAXParseException e ) throws SAXException 1798 { 1799 throw e; 1800 } 1801 1802 } ); 1803 1804 final javax.xml.validation.Schema schema = f.newSchema( sources.toArray( new Source[ sources.size() ] ) ); 1805 1806 if ( this.isLoggable( Level.FINE ) ) 1807 { 1808 final StringBuilder schemaInfo = new StringBuilder( sources.size() * 50 ); 1809 1810 for ( final Source s : sources ) 1811 { 1812 schemaInfo.append( ", " ).append( s.getSystemId() ); 1813 } 1814 1815 this.log( Level.FINE, getMessage( "creatingSchema", schemaInfo.substring( 2 ), 1816 System.currentTimeMillis() - t0 ), null ); 1817 1818 } 1819 1820 return schema; 1821 } 1822 catch ( final IOException e ) 1823 { 1824 throw new ModelException( getMessage( e ), e ); 1825 } 1826 catch ( final SAXException e ) 1827 { 1828 String message = getMessage( e ); 1829 if ( message == null && e.getException() != null ) 1830 { 1831 message = getMessage( e.getException() ); 1832 } 1833 1834 throw new ModelException( message, e ); 1835 } 1836 } 1837 1838 private JAXBContext createContext( final Schemas schemas, final String model, final URI publicId ) 1839 throws ModelException 1840 { 1841 if ( model != null && publicId != null ) 1842 { 1843 throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() ); 1844 } 1845 1846 try 1847 { 1848 StringBuilder packageNames = null; 1849 final long t0 = System.currentTimeMillis(); 1850 1851 if ( schemas != null ) 1852 { 1853 packageNames = new StringBuilder( schemas.getSchema().size() * 25 ); 1854 1855 for ( final Schema schema : schemas.getSchema() ) 1856 { 1857 if ( schema.getContextId() != null ) 1858 { 1859 packageNames.append( ':' ).append( schema.getContextId() ); 1860 } 1861 } 1862 } 1863 1864 if ( packageNames == null || packageNames.length() == 0 ) 1865 { 1866 if ( model != null ) 1867 { 1868 throw new ModelException( getMessage( "missingSchemasForModel", model ) ); 1869 } 1870 if ( publicId != null ) 1871 { 1872 throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) ); 1873 } 1874 } 1875 1876 final JAXBContext context = JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() ); 1877 1878 if ( this.isLoggable( Level.FINE ) ) 1879 { 1880 this.log( Level.FINE, getMessage( "creatingContext", packageNames.substring( 1 ), 1881 System.currentTimeMillis() - t0 ), null ); 1882 } 1883 1884 return context; 1885 } 1886 catch ( final JAXBException e ) 1887 { 1888 String message = getMessage( e ); 1889 if ( message == null && e.getLinkedException() != null ) 1890 { 1891 message = getMessage( e.getLinkedException() ); 1892 } 1893 1894 throw new ModelException( message, e ); 1895 } 1896 } 1897 1898 private Marshaller createMarshaller( final String model, final URI publicId ) 1899 throws ModelException 1900 { 1901 if ( model != null && publicId != null ) 1902 { 1903 throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() ); 1904 } 1905 1906 Schemas schemas = null; 1907 1908 if ( model != null ) 1909 { 1910 schemas = this.getModlets().getSchemas( model ); 1911 } 1912 1913 if ( publicId != null ) 1914 { 1915 schemas = this.getModlets().getSchemas( publicId ); 1916 } 1917 1918 try 1919 { 1920 StringBuilder packageNames = null; 1921 StringBuilder schemaLocation = null; 1922 final long t0 = System.currentTimeMillis(); 1923 1924 if ( schemas != null ) 1925 { 1926 packageNames = new StringBuilder( schemas.getSchema().size() * 25 ); 1927 schemaLocation = new StringBuilder( schemas.getSchema().size() * 50 ); 1928 1929 for ( final Schema schema : schemas.getSchema() ) 1930 { 1931 if ( schema.getContextId() != null ) 1932 { 1933 packageNames.append( ':' ).append( schema.getContextId() ); 1934 } 1935 if ( schema.getPublicId() != null && schema.getSystemId() != null ) 1936 { 1937 schemaLocation.append( ' ' ).append( schema.getPublicId() ).append( ' ' ). 1938 append( schema.getSystemId() ); 1939 1940 } 1941 } 1942 } 1943 1944 if ( packageNames == null || packageNames.length() == 0 ) 1945 { 1946 if ( model != null ) 1947 { 1948 throw new ModelException( getMessage( "missingSchemasForModel", model ) ); 1949 } 1950 if ( publicId != null ) 1951 { 1952 throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) ); 1953 } 1954 } 1955 1956 final Marshaller m = 1957 JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() ).createMarshaller(); 1958 1959 if ( schemaLocation != null && schemaLocation.length() != 0 ) 1960 { 1961 m.setProperty( Marshaller.JAXB_SCHEMA_LOCATION, schemaLocation.substring( 1 ) ); 1962 } 1963 1964 MarshallerListenerList listenerList = null; 1965 1966 if ( model != null ) 1967 { 1968 final Collection<? extends Marshaller.Listener> listeners = 1969 this.createServiceObjects( model, MARSHALLER_LISTENER_SERVICE, Marshaller.Listener.class ); 1970 1971 if ( !listeners.isEmpty() ) 1972 { 1973 listenerList = new MarshallerListenerList(); 1974 listenerList.getListeners().addAll( listeners ); 1975 m.setListener( listenerList ); 1976 } 1977 } 1978 1979 if ( this.isLoggable( Level.FINE ) ) 1980 { 1981 if ( listenerList == null ) 1982 { 1983 this.log( Level.FINE, getMessage( "creatingMarshaller", packageNames.substring( 1 ), 1984 schemaLocation.substring( 1 ), 1985 System.currentTimeMillis() - t0 ), null ); 1986 1987 } 1988 else 1989 { 1990 final StringBuilder b = new StringBuilder( listenerList.getListeners().size() * 100 ); 1991 1992 for ( int i = 0, s0 = listenerList.getListeners().size(); i < s0; i++ ) 1993 { 1994 b.append( ',' ).append( listenerList.getListeners().get( i ) ); 1995 } 1996 1997 this.log( Level.FINE, getMessage( "creatingMarshallerWithListeners", packageNames.substring( 1 ), 1998 schemaLocation.substring( 1 ), b.substring( 1 ), 1999 System.currentTimeMillis() - t0 ), null ); 2000 2001 } 2002 } 2003 2004 return m; 2005 } 2006 catch ( final JAXBException e ) 2007 { 2008 String message = getMessage( e ); 2009 if ( message == null && e.getLinkedException() != null ) 2010 { 2011 message = getMessage( e.getLinkedException() ); 2012 } 2013 2014 throw new ModelException( message, e ); 2015 } 2016 } 2017 2018 private Unmarshaller createUnmarshaller( final String model, final URI publicId ) 2019 throws ModelException 2020 { 2021 if ( model != null && publicId != null ) 2022 { 2023 throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() ); 2024 } 2025 2026 Schemas schemas = null; 2027 2028 if ( model != null ) 2029 { 2030 schemas = this.getModlets().getSchemas( model ); 2031 } 2032 2033 if ( publicId != null ) 2034 { 2035 schemas = this.getModlets().getSchemas( publicId ); 2036 } 2037 2038 try 2039 { 2040 StringBuilder packageNames = null; 2041 final long t0 = System.currentTimeMillis(); 2042 2043 if ( schemas != null ) 2044 { 2045 packageNames = new StringBuilder( schemas.getSchema().size() * 25 ); 2046 2047 for ( final Schema schema : schemas.getSchema() ) 2048 { 2049 if ( schema.getContextId() != null ) 2050 { 2051 packageNames.append( ':' ).append( schema.getContextId() ); 2052 } 2053 } 2054 } 2055 2056 if ( packageNames == null || packageNames.length() == 0 ) 2057 { 2058 if ( model != null ) 2059 { 2060 throw new ModelException( getMessage( "missingSchemasForModel", model ) ); 2061 } 2062 if ( publicId != null ) 2063 { 2064 throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) ); 2065 } 2066 } 2067 2068 final Unmarshaller u = 2069 JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() ).createUnmarshaller(); 2070 2071 UnmarshallerListenerList listenerList = null; 2072 2073 if ( model != null ) 2074 { 2075 final Collection<? extends Unmarshaller.Listener> listeners = 2076 this.createServiceObjects( model, UNMARSHALLER_LISTENER_SERVICE, Unmarshaller.Listener.class ); 2077 2078 if ( !listeners.isEmpty() ) 2079 { 2080 listenerList = new UnmarshallerListenerList(); 2081 listenerList.getListeners().addAll( listeners ); 2082 u.setListener( listenerList ); 2083 } 2084 } 2085 2086 if ( this.isLoggable( Level.FINE ) ) 2087 { 2088 if ( listenerList == null ) 2089 { 2090 this.log( Level.FINE, getMessage( "creatingUnmarshaller", packageNames.substring( 1 ), 2091 System.currentTimeMillis() - t0 ), null ); 2092 2093 } 2094 else 2095 { 2096 final StringBuilder b = new StringBuilder( listenerList.getListeners().size() * 100 ); 2097 2098 for ( int i = 0, s0 = listenerList.getListeners().size(); i < s0; i++ ) 2099 { 2100 b.append( ',' ).append( listenerList.getListeners().get( i ) ); 2101 } 2102 2103 this.log( Level.FINE, getMessage( "creatingUnmarshallerWithListeners", 2104 packageNames.substring( 1 ), b.substring( 1 ), 2105 System.currentTimeMillis() - t0 ), null ); 2106 2107 } 2108 } 2109 2110 return u; 2111 } 2112 catch ( final JAXBException e ) 2113 { 2114 String message = getMessage( e ); 2115 if ( message == null && e.getLinkedException() != null ) 2116 { 2117 message = getMessage( e.getLinkedException() ); 2118 } 2119 2120 throw new ModelException( message, e ); 2121 } 2122 } 2123 2124 private static int ordinalOf( final Object serviceObject ) 2125 { 2126 int ordinal = 0; 2127 2128 if ( serviceObject instanceof ModletProvider ) 2129 { 2130 ordinal = ( (ModletProvider) serviceObject ).getOrdinal(); 2131 } 2132 if ( serviceObject instanceof ModletProcessor ) 2133 { 2134 ordinal = ( (ModletProcessor) serviceObject ).getOrdinal(); 2135 } 2136 if ( serviceObject instanceof ModletValidator ) 2137 { 2138 ordinal = ( (ModletValidator) serviceObject ).getOrdinal(); 2139 } 2140 if ( serviceObject instanceof ServiceFactory ) 2141 { 2142 ordinal = ( (ServiceFactory) serviceObject ).getOrdinal(); 2143 } 2144 2145 return ordinal; 2146 } 2147 2148 private static String getMessage( final String key, final Object... arguments ) 2149 { 2150 return MessageFormat.format( ResourceBundle.getBundle( 2151 DefaultModelContext.class.getName().replace( '.', '/' ) ).getString( key ), arguments ); 2152 2153 } 2154 2155 private static String getMessage( final Throwable t ) 2156 { 2157 return t != null 2158 ? t.getMessage() != null && t.getMessage().trim().length() > 0 2159 ? t.getMessage() 2160 : getMessage( t.getCause() ) 2161 : null; 2162 2163 } 2164 2165} 2166 2167/** 2168 * {@code ErrorHandler} collecting {@code ModelValidationReport} details. 2169 * 2170 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 2171 * @version $JOMC: DefaultModelContext.java 5051 2015-05-30 17:29:32Z schulte $ 2172 */ 2173class ModelErrorHandler extends DefaultHandler 2174{ 2175 2176 /** 2177 * The context of the instance. 2178 */ 2179 private ModelContext context; 2180 2181 /** 2182 * The report of the instance. 2183 */ 2184 private ModelValidationReport report; 2185 2186 /** 2187 * Creates a new {@code ModelErrorHandler} instance taking a context. 2188 * 2189 * @param context The context of the instance. 2190 */ 2191 ModelErrorHandler( final ModelContext context ) 2192 { 2193 this( context, null ); 2194 } 2195 2196 /** 2197 * Creates a new {@code ModelErrorHandler} instance taking a report to use for collecting validation events. 2198 * 2199 * @param context The context of the instance. 2200 * @param report A report to use for collecting validation events. 2201 */ 2202 ModelErrorHandler( final ModelContext context, final ModelValidationReport report ) 2203 { 2204 super(); 2205 this.context = context; 2206 this.report = report; 2207 } 2208 2209 /** 2210 * Gets the report of the instance. 2211 * 2212 * @return The report of the instance. 2213 */ 2214 public ModelValidationReport getReport() 2215 { 2216 if ( this.report == null ) 2217 { 2218 this.report = new ModelValidationReport(); 2219 } 2220 2221 return this.report; 2222 } 2223 2224 @Override 2225 public void warning( final SAXParseException exception ) throws SAXException 2226 { 2227 String message = getMessage( exception ); 2228 if ( message == null && exception.getException() != null ) 2229 { 2230 message = getMessage( exception.getException() ); 2231 } 2232 2233 if ( this.context != null && this.context.isLoggable( Level.FINE ) ) 2234 { 2235 this.context.log( Level.FINE, message, exception ); 2236 } 2237 2238 this.getReport().getDetails().add( new ModelValidationReport.Detail( 2239 "W3C XML 1.0 Recommendation - Warning condition", Level.WARNING, message, null ) ); 2240 2241 } 2242 2243 @Override 2244 public void error( final SAXParseException exception ) throws SAXException 2245 { 2246 String message = getMessage( exception ); 2247 if ( message == null && exception.getException() != null ) 2248 { 2249 message = getMessage( exception.getException() ); 2250 } 2251 2252 if ( this.context != null && this.context.isLoggable( Level.FINE ) ) 2253 { 2254 this.context.log( Level.FINE, message, exception ); 2255 } 2256 2257 this.getReport().getDetails().add( new ModelValidationReport.Detail( 2258 "W3C XML 1.0 Recommendation - Section 1.2 - Error", Level.SEVERE, message, null ) ); 2259 2260 } 2261 2262 @Override 2263 public void fatalError( final SAXParseException exception ) throws SAXException 2264 { 2265 String message = getMessage( exception ); 2266 if ( message == null && exception.getException() != null ) 2267 { 2268 message = getMessage( exception.getException() ); 2269 } 2270 2271 if ( this.context != null && this.context.isLoggable( Level.FINE ) ) 2272 { 2273 this.context.log( Level.FINE, message, exception ); 2274 } 2275 2276 this.getReport().getDetails().add( new ModelValidationReport.Detail( 2277 "W3C XML 1.0 Recommendation - Section 1.2 - Fatal Error", Level.SEVERE, message, null ) ); 2278 2279 } 2280 2281 private static String getMessage( final Throwable t ) 2282 { 2283 return t != null 2284 ? t.getMessage() != null && t.getMessage().trim().length() > 0 2285 ? t.getMessage() 2286 : getMessage( t.getCause() ) 2287 : null; 2288 2289 } 2290 2291} 2292 2293/** 2294 * List of {@code Marshaller.Listener}s. 2295 * 2296 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 2297 * @version $JOMC: DefaultModelContext.java 5051 2015-05-30 17:29:32Z schulte $ 2298 * @since 1.2 2299 */ 2300class MarshallerListenerList extends Marshaller.Listener 2301{ 2302 2303 /** 2304 * The {@code Marshaller.Listener}s of the instance. 2305 */ 2306 private List<Marshaller.Listener> listeners; 2307 2308 /** 2309 * Creates a new {@code MarshallerListenerList} instance. 2310 */ 2311 MarshallerListenerList() 2312 { 2313 super(); 2314 } 2315 2316 /** 2317 * Gets the listeners of the instance. 2318 * <p> 2319 * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make 2320 * to the returned list will be present inside the object. This is why there is no {@code set} method for the 2321 * listeners property. 2322 * </p> 2323 * 2324 * @return The list of listeners of the instance. 2325 */ 2326 List<Marshaller.Listener> getListeners() 2327 { 2328 if ( this.listeners == null ) 2329 { 2330 this.listeners = new ArrayList<Marshaller.Listener>(); 2331 } 2332 2333 return this.listeners; 2334 } 2335 2336 @Override 2337 public void beforeMarshal( final Object source ) 2338 { 2339 for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ ) 2340 { 2341 this.getListeners().get( i ).beforeMarshal( source ); 2342 } 2343 } 2344 2345 @Override 2346 public void afterMarshal( final Object source ) 2347 { 2348 for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ ) 2349 { 2350 this.getListeners().get( i ).afterMarshal( source ); 2351 } 2352 } 2353 2354} 2355 2356/** 2357 * List of {@code Unmarshaller.Listener}s. 2358 * 2359 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 2360 * @version $JOMC: DefaultModelContext.java 5051 2015-05-30 17:29:32Z schulte $ 2361 * @since 1.2 2362 */ 2363class UnmarshallerListenerList extends Unmarshaller.Listener 2364{ 2365 2366 /** 2367 * The {@code Unmarshaller.Listener}s of the instance. 2368 */ 2369 private List<Unmarshaller.Listener> listeners; 2370 2371 /** 2372 * Creates a new {@code UnmarshallerListenerList} instance. 2373 */ 2374 UnmarshallerListenerList() 2375 { 2376 super(); 2377 } 2378 2379 /** 2380 * Gets the listeners of the instance. 2381 * <p> 2382 * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make 2383 * to the returned list will be present inside the object. This is why there is no {@code set} method for the 2384 * listeners property. 2385 * </p> 2386 * 2387 * @return The list of listeners of the instance. 2388 */ 2389 List<Unmarshaller.Listener> getListeners() 2390 { 2391 if ( this.listeners == null ) 2392 { 2393 this.listeners = new ArrayList<Unmarshaller.Listener>(); 2394 } 2395 2396 return this.listeners; 2397 } 2398 2399 @Override 2400 public void beforeUnmarshal( final Object target, final Object parent ) 2401 { 2402 for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ ) 2403 { 2404 this.getListeners().get( i ).beforeUnmarshal( target, parent ); 2405 } 2406 } 2407 2408 @Override 2409 public void afterUnmarshal( final Object target, final Object parent ) 2410 { 2411 for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ ) 2412 { 2413 this.getListeners().get( i ).afterUnmarshal( target, parent ); 2414 } 2415 } 2416 2417}