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