1 /* 2 * Copyright (C) Christian Schulte <cs@schulte.it>, 2005-206 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * o Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * o Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 19 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $JOMC: ModelContext.java 5051 2015-05-30 17:29:32Z schulte $ 29 * 30 */ 31 package org.jomc.modlet; 32 33 import java.io.IOException; 34 import java.lang.reflect.Constructor; 35 import java.lang.reflect.InvocationTargetException; 36 import java.net.URI; 37 import java.net.URL; 38 import java.text.MessageFormat; 39 import java.util.Collection; 40 import java.util.Collections; 41 import java.util.Enumeration; 42 import java.util.HashMap; 43 import java.util.LinkedList; 44 import java.util.List; 45 import java.util.Locale; 46 import java.util.Map; 47 import java.util.ResourceBundle; 48 import java.util.Set; 49 import java.util.logging.Level; 50 import javax.xml.bind.JAXBContext; 51 import javax.xml.bind.Marshaller; 52 import javax.xml.bind.Unmarshaller; 53 import javax.xml.transform.Source; 54 import org.w3c.dom.ls.LSResourceResolver; 55 import org.xml.sax.EntityResolver; 56 57 /** 58 * Model context interface. 59 * <p> 60 * <b>Use Cases:</b><br/><ul> 61 * <li>{@link #createContext(java.lang.String) }</li> 62 * <li>{@link #createEntityResolver(java.lang.String) }</li> 63 * <li>{@link #createMarshaller(java.lang.String) }</li> 64 * <li>{@link #createResourceResolver(java.lang.String) }</li> 65 * <li>{@link #createSchema(java.lang.String) }</li> 66 * <li>{@link #createUnmarshaller(java.lang.String) }</li> 67 * <li>{@link #findModel(java.lang.String) }</li> 68 * <li>{@link #findModel(org.jomc.modlet.Model) }</li> 69 * <li>{@link #processModel(org.jomc.modlet.Model) }</li> 70 * <li>{@link #validateModel(org.jomc.modlet.Model) }</li> 71 * <li>{@link #validateModel(java.lang.String, javax.xml.transform.Source) }</li> 72 * </ul> 73 * 74 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 75 * @version $JOMC: ModelContext.java 5051 2015-05-30 17:29:32Z schulte $ 76 * 77 * @see ModelContextFactory 78 */ 79 public abstract class ModelContext 80 { 81 82 /** 83 * Listener interface. 84 */ 85 public abstract static class Listener 86 { 87 88 /** 89 * Creates a new {@code Listener} instance. 90 */ 91 public Listener() 92 { 93 super(); 94 } 95 96 /** 97 * Gets called on logging. 98 * 99 * @param level The level of the event. 100 * @param message The message of the event or {@code null}. 101 * @param t The throwable of the event or {@code null}. 102 * 103 * @throws NullPointerException if {@code level} is {@code null}. 104 */ 105 public void onLog( final Level level, final String message, final Throwable t ) 106 { 107 if ( level == null ) 108 { 109 throw new NullPointerException( "level" ); 110 } 111 } 112 113 } 114 115 /** 116 * Default {@code http://jomc.org/modlet} namespace schema system id. 117 * 118 * @see #getDefaultModletSchemaSystemId() 119 */ 120 private static final String DEFAULT_MODLET_SCHEMA_SYSTEM_ID = 121 "http://xml.jomc.org/modlet/jomc-modlet-1.9.xsd"; 122 123 /** 124 * Log level events are logged at by default. 125 * 126 * @see #getDefaultLogLevel() 127 */ 128 private static final Level DEFAULT_LOG_LEVEL = Level.WARNING; 129 130 /** 131 * Default log level. 132 */ 133 private static volatile Level defaultLogLevel; 134 135 /** 136 * Default {@code http://jomc.org/model/modlet} namespace schema system id. 137 */ 138 private static volatile String defaultModletSchemaSystemId; 139 140 /** 141 * Class name of the {@code ModelContext} implementation. 142 */ 143 @Deprecated 144 private static volatile String modelContextClassName; 145 146 /** 147 * The attributes of the instance. 148 */ 149 private final Map<String, Object> attributes = new HashMap<String, Object>(); 150 151 /** 152 * The class loader of the instance. 153 */ 154 private ClassLoader classLoader; 155 156 /** 157 * Flag indicating the {@code classLoader} field is initialized. 158 * 159 * @since 1.2 160 */ 161 private boolean classLoaderSet; 162 163 /** 164 * The listeners of the instance. 165 */ 166 private List<Listener> listeners; 167 168 /** 169 * Log level of the instance. 170 */ 171 private Level logLevel; 172 173 /** 174 * The {@code Modlets} of the instance. 175 */ 176 private Modlets modlets; 177 178 /** 179 * Modlet namespace schema system id of the instance. 180 */ 181 private String modletSchemaSystemId; 182 183 /** 184 * Creates a new {@code ModelContext} instance. 185 * 186 * @since 1.2 187 */ 188 public ModelContext() 189 { 190 super(); 191 this.classLoader = null; 192 this.classLoaderSet = false; 193 } 194 195 /** 196 * Creates a new {@code ModelContext} instance taking a class loader. 197 * 198 * @param classLoader The class loader of the context. 199 * 200 * @see #getClassLoader() 201 */ 202 public ModelContext( final ClassLoader classLoader ) 203 { 204 super(); 205 this.classLoader = classLoader; 206 this.classLoaderSet = true; 207 } 208 209 /** 210 * Gets a set holding the names of all attributes of the context. 211 * 212 * @return An unmodifiable set holding the names of all attributes of the context. 213 * 214 * @see #clearAttribute(java.lang.String) 215 * @see #getAttribute(java.lang.String) 216 * @see #getAttribute(java.lang.String, java.lang.Object) 217 * @see #setAttribute(java.lang.String, java.lang.Object) 218 * @since 1.2 219 */ 220 public Set<String> getAttributeNames() 221 { 222 return Collections.unmodifiableSet( this.attributes.keySet() ); 223 } 224 225 /** 226 * Gets an attribute of the context. 227 * 228 * @param name The name of the attribute to get. 229 * 230 * @return The value of the attribute with name {@code name}; {@code null} if no attribute matching {@code name} is 231 * found. 232 * 233 * @throws NullPointerException if {@code name} is {@code null}. 234 * 235 * @see #getAttribute(java.lang.String, java.lang.Object) 236 * @see #setAttribute(java.lang.String, java.lang.Object) 237 * @see #clearAttribute(java.lang.String) 238 */ 239 public Object getAttribute( final String name ) 240 { 241 if ( name == null ) 242 { 243 throw new NullPointerException( "name" ); 244 } 245 246 return this.attributes.get( name ); 247 } 248 249 /** 250 * Gets an attribute of the context. 251 * 252 * @param name The name of the attribute to get. 253 * @param def The value to return if no attribute matching {@code name} is found. 254 * 255 * @return The value of the attribute with name {@code name}; {@code def} if no such attribute is found. 256 * 257 * @throws NullPointerException if {@code name} is {@code null}. 258 * 259 * @see #getAttribute(java.lang.String) 260 * @see #setAttribute(java.lang.String, java.lang.Object) 261 * @see #clearAttribute(java.lang.String) 262 */ 263 public Object getAttribute( final String name, final Object def ) 264 { 265 if ( name == null ) 266 { 267 throw new NullPointerException( "name" ); 268 } 269 270 Object value = this.getAttribute( name ); 271 272 if ( value == null ) 273 { 274 value = def; 275 } 276 277 return value; 278 } 279 280 /** 281 * Sets an attribute in the context. 282 * 283 * @param name The name of the attribute to set. 284 * @param value The value of the attribute to set. 285 * 286 * @return The previous value of the attribute with name {@code name}; {@code null} if no such value is found. 287 * 288 * @throws NullPointerException if {@code name} or {@code value} is {@code null}. 289 * 290 * @see #getAttribute(java.lang.String) 291 * @see #getAttribute(java.lang.String, java.lang.Object) 292 * @see #clearAttribute(java.lang.String) 293 */ 294 public Object setAttribute( final String name, final Object value ) 295 { 296 if ( name == null ) 297 { 298 throw new NullPointerException( "name" ); 299 } 300 if ( value == null ) 301 { 302 throw new NullPointerException( "value" ); 303 } 304 305 return this.attributes.put( name, value ); 306 } 307 308 /** 309 * Removes an attribute from the context. 310 * 311 * @param name The name of the attribute to remove. 312 * 313 * @throws NullPointerException if {@code name} is {@code null}. 314 * 315 * @see #getAttribute(java.lang.String) 316 * @see #getAttribute(java.lang.String, java.lang.Object) 317 * @see #setAttribute(java.lang.String, java.lang.Object) 318 */ 319 public void clearAttribute( final String name ) 320 { 321 if ( name == null ) 322 { 323 throw new NullPointerException( "name" ); 324 } 325 326 this.attributes.remove( name ); 327 } 328 329 /** 330 * Gets the class loader of the context. 331 * 332 * @return The class loader of the context or {@code null}, indicating the bootstrap class loader. 333 * 334 * @see #findClass(java.lang.String) 335 * @see #findResource(java.lang.String) 336 * @see #findResources(java.lang.String) 337 */ 338 public ClassLoader getClassLoader() 339 { 340 if ( !this.classLoaderSet ) 341 { 342 this.classLoader = this.getClass().getClassLoader(); 343 this.classLoaderSet = true; 344 } 345 346 return this.classLoader; 347 } 348 349 /** 350 * Gets the listeners of the context. 351 * <p> 352 * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make 353 * to the returned list will be present inside the object. This is why there is no {@code set} method for the 354 * listeners property. 355 * </p> 356 * 357 * @return The list of listeners of the context. 358 * 359 * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable) 360 */ 361 public List<Listener> getListeners() 362 { 363 if ( this.listeners == null ) 364 { 365 this.listeners = new LinkedList<Listener>(); 366 } 367 368 return this.listeners; 369 } 370 371 /** 372 * Gets the default {@code http://jomc.org/modlet} namespace schema system id. 373 * <p> 374 * The default {@code http://jomc.org/modlet} namespace schema system id is controlled by system property 375 * {@code org.jomc.modlet.ModelContext.defaultModletSchemaSystemId} holding a system id URI. 376 * If that property is not set, the {@code http://xml.jomc.org/modlet/jomc-modlet-1.9.xsd} default is 377 * returned. 378 * </p> 379 * 380 * @return The default system id of the {@code http://jomc.org/modlet} namespace schema. 381 * 382 * @see #setDefaultModletSchemaSystemId(java.lang.String) 383 */ 384 public static String getDefaultModletSchemaSystemId() 385 { 386 if ( defaultModletSchemaSystemId == null ) 387 { 388 defaultModletSchemaSystemId = System.getProperty( 389 "org.jomc.modlet.ModelContext.defaultModletSchemaSystemId", DEFAULT_MODLET_SCHEMA_SYSTEM_ID ); 390 391 } 392 393 return defaultModletSchemaSystemId; 394 } 395 396 /** 397 * Sets the default {@code http://jomc.org/modlet} namespace schema system id. 398 * 399 * @param value The new default {@code http://jomc.org/modlet} namespace schema system id or {@code null}. 400 * 401 * @see #getDefaultModletSchemaSystemId() 402 */ 403 public static void setDefaultModletSchemaSystemId( final String value ) 404 { 405 defaultModletSchemaSystemId = value; 406 } 407 408 /** 409 * Gets the {@code http://jomc.org/modlet} namespace schema system id of the context. 410 * 411 * @return The {@code http://jomc.org/modlet} namespace schema system id of the context. 412 * 413 * @see #getDefaultModletSchemaSystemId() 414 * @see #setModletSchemaSystemId(java.lang.String) 415 */ 416 public final String getModletSchemaSystemId() 417 { 418 if ( this.modletSchemaSystemId == null ) 419 { 420 this.modletSchemaSystemId = getDefaultModletSchemaSystemId(); 421 422 if ( this.isLoggable( Level.CONFIG ) ) 423 { 424 this.log( Level.CONFIG, 425 getMessage( "defaultModletSchemaSystemIdInfo", this.modletSchemaSystemId ), null ); 426 427 } 428 } 429 430 return this.modletSchemaSystemId; 431 } 432 433 /** 434 * Sets the {@code http://jomc.org/modlet} namespace schema system id of the context. 435 * 436 * @param value The new {@code http://jomc.org/modlet} namespace schema system id or {@code null}. 437 * 438 * @see #getModletSchemaSystemId() 439 */ 440 public final void setModletSchemaSystemId( final String value ) 441 { 442 final String oldModletSchemaSystemId = this.getModletSchemaSystemId(); 443 this.modletSchemaSystemId = value; 444 445 if ( this.modlets != null ) 446 { 447 for ( int i = 0, s0 = this.modlets.getModlet().size(); i < s0; i++ ) 448 { 449 final Modlet m = this.modlets.getModlet().get( i ); 450 451 if ( m.getSchemas() != null ) 452 { 453 final Schema s = m.getSchemas().getSchemaBySystemId( oldModletSchemaSystemId ); 454 455 if ( s != null ) 456 { 457 s.setSystemId( value ); 458 } 459 } 460 } 461 } 462 } 463 464 /** 465 * Gets the default log level events are logged at. 466 * <p> 467 * The default log level is controlled by system property 468 * {@code org.jomc.modlet.ModelContext.defaultLogLevel} holding the log level to log events at by default. 469 * If that property is not set, the {@code WARNING} default is returned. 470 * </p> 471 * 472 * @return The log level events are logged at by default. 473 * 474 * @see #getLogLevel() 475 * @see Level#parse(java.lang.String) 476 */ 477 public static Level getDefaultLogLevel() 478 { 479 if ( defaultLogLevel == null ) 480 { 481 defaultLogLevel = Level.parse( System.getProperty( 482 "org.jomc.modlet.ModelContext.defaultLogLevel", DEFAULT_LOG_LEVEL.getName() ) ); 483 484 } 485 486 return defaultLogLevel; 487 } 488 489 /** 490 * Sets the default log level events are logged at. 491 * 492 * @param value The new default level events are logged at or {@code null}. 493 * 494 * @see #getDefaultLogLevel() 495 */ 496 public static void setDefaultLogLevel( final Level value ) 497 { 498 defaultLogLevel = value; 499 } 500 501 /** 502 * Gets the log level of the context. 503 * 504 * @return The log level of the context. 505 * 506 * @see #getDefaultLogLevel() 507 * @see #setLogLevel(java.util.logging.Level) 508 * @see #isLoggable(java.util.logging.Level) 509 */ 510 public final Level getLogLevel() 511 { 512 if ( this.logLevel == null ) 513 { 514 this.logLevel = getDefaultLogLevel(); 515 516 if ( this.isLoggable( Level.CONFIG ) ) 517 { 518 this.log( Level.CONFIG, getMessage( "defaultLogLevelInfo", this.logLevel.getLocalizedName() ), null ); 519 } 520 } 521 522 return this.logLevel; 523 } 524 525 /** 526 * Sets the log level of the context. 527 * 528 * @param value The new log level of the context or {@code null}. 529 * 530 * @see #getLogLevel() 531 * @see #isLoggable(java.util.logging.Level) 532 */ 533 public final void setLogLevel( final Level value ) 534 { 535 this.logLevel = value; 536 } 537 538 /** 539 * Checks if a message at a given level is provided to the listeners of the context. 540 * 541 * @param level The level to test. 542 * 543 * @return {@code true}, if messages at {@code level} are provided to the listeners of the context; {@code false}, 544 * if messages at {@code level} are not provided to the listeners of the context. 545 * 546 * @throws NullPointerException if {@code level} is {@code null}. 547 * 548 * @see #getLogLevel() 549 * @see #setLogLevel(java.util.logging.Level) 550 */ 551 public boolean isLoggable( final Level level ) 552 { 553 if ( level == null ) 554 { 555 throw new NullPointerException( "level" ); 556 } 557 558 return level.intValue() >= this.getLogLevel().intValue(); 559 } 560 561 /** 562 * Notifies all listeners of the context. 563 * 564 * @param level The level of the event. 565 * @param message The message of the event or {@code null}. 566 * @param throwable The throwable of the event {@code null}. 567 * 568 * @throws NullPointerException if {@code level} is {@code null}. 569 * 570 * @see #getListeners() 571 * @see #isLoggable(java.util.logging.Level) 572 */ 573 public void log( final Level level, final String message, final Throwable throwable ) 574 { 575 if ( level == null ) 576 { 577 throw new NullPointerException( "level" ); 578 } 579 580 if ( this.isLoggable( level ) ) 581 { 582 for ( final Listener l : this.getListeners() ) 583 { 584 l.onLog( level, message, throwable ); 585 } 586 } 587 } 588 589 /** 590 * Gets the {@code Modlets} of the context. 591 * <p> 592 * If no {@code Modlets} have been set using the {@code setModlets} method, this method calls the 593 * {@code findModlets} method and the {@code processModlets} method to initialize the {@code Modlets} of the 594 * context. 595 * </p> 596 * <p> 597 * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make 598 * to the returned list will be present inside the object. 599 * </p> 600 * 601 * @return The {@code Modlets} of the context. 602 * 603 * @throws ModelException if getting the {@code Modlets} of the context fails. 604 * 605 * @see #setModlets(org.jomc.modlet.Modlets) 606 * @see #findModlets(org.jomc.modlet.Modlets) 607 * @see #processModlets(org.jomc.modlet.Modlets) 608 * @see #validateModlets(org.jomc.modlet.Modlets) 609 */ 610 public final Modlets getModlets() throws ModelException 611 { 612 if ( this.modlets == null ) 613 { 614 final Modlet modlet = new Modlet(); 615 modlet.setModel( ModletObject.MODEL_PUBLIC_ID ); 616 modlet.setName( getMessage( "projectName" ) ); 617 modlet.setVendor( getMessage( "projectVendor" ) ); 618 modlet.setVersion( getMessage( "projectVersion" ) ); 619 modlet.setSchemas( new Schemas() ); 620 621 final Schema schema = new Schema(); 622 schema.setPublicId( ModletObject.MODEL_PUBLIC_ID ); 623 schema.setSystemId( this.getModletSchemaSystemId() ); 624 schema.setContextId( ModletObject.class.getPackage().getName() ); 625 schema.setClasspathId( ModletObject.class.getPackage().getName().replace( '.', '/' ) 626 + "/jomc-modlet-1.9.xsd" ); 627 628 modlet.getSchemas().getSchema().add( schema ); 629 630 this.modlets = new Modlets(); 631 this.modlets.getModlet().add( modlet ); 632 633 long t0 = System.currentTimeMillis(); 634 final Modlets provided = this.findModlets( this.modlets ); 635 636 if ( this.isLoggable( Level.FINE ) ) 637 { 638 this.log( Level.FINE, getMessage( "findModletsReport", 639 provided != null ? provided.getModlet().size() : 0, 640 System.currentTimeMillis() - t0 ), null ); 641 642 } 643 644 if ( provided != null ) 645 { 646 this.modlets = provided; 647 } 648 649 t0 = System.currentTimeMillis(); 650 final Modlets processed = this.processModlets( this.modlets ); 651 652 if ( this.isLoggable( Level.FINE ) ) 653 { 654 this.log( Level.FINE, getMessage( "processModletsReport", 655 processed != null ? processed.getModlet().size() : 0, 656 System.currentTimeMillis() - t0 ), null ); 657 } 658 659 if ( processed != null ) 660 { 661 this.modlets = processed; 662 } 663 664 t0 = System.currentTimeMillis(); 665 final ModelValidationReport report = this.validateModlets( this.modlets ); 666 667 if ( this.isLoggable( Level.FINE ) ) 668 { 669 this.log( Level.FINE, getMessage( "validateModletsReport", 670 this.modlets.getModlet().size(), 671 System.currentTimeMillis() - t0 ), null ); 672 } 673 674 for ( final ModelValidationReport.Detail detail : report.getDetails() ) 675 { 676 if ( this.isLoggable( detail.getLevel() ) ) 677 { 678 this.log( detail.getLevel(), detail.getMessage(), null ); 679 } 680 } 681 682 if ( !report.isModelValid() ) 683 { 684 this.modlets = null; 685 throw new ModelException( getMessage( "invalidModlets" ) ); 686 } 687 } 688 689 return this.modlets; 690 } 691 692 /** 693 * Sets the {@code Modlets} of the context. 694 * 695 * @param value The new {@code Modlets} of the context or {@code null}. 696 * 697 * @see #getModlets() 698 */ 699 public final void setModlets( final Modlets value ) 700 { 701 this.modlets = value; 702 } 703 704 /** 705 * Searches the context for a class with a given name. 706 * 707 * @param name The name of the class to search. 708 * 709 * @return A class object of the class with name {@code name} or {@code null}, if no such class is found. 710 * 711 * @throws NullPointerException if {@code name} is {@code null}. 712 * @throws ModelException if searching fails. 713 * 714 * @see #getClassLoader() 715 */ 716 public Class<?> findClass( final String name ) throws ModelException 717 { 718 if ( name == null ) 719 { 720 throw new NullPointerException( "name" ); 721 } 722 723 try 724 { 725 return Class.forName( name, false, this.getClassLoader() ); 726 } 727 catch ( final ClassNotFoundException e ) 728 { 729 if ( this.isLoggable( Level.FINE ) ) 730 { 731 this.log( Level.FINE, getMessage( e ), e ); 732 } 733 734 return null; 735 } 736 } 737 738 /** 739 * Searches the context for a resource with a given name. 740 * 741 * @param name The name of the resource to search. 742 * 743 * @return An URL object for reading the resource or {@code null}, if no such resource is found. 744 * 745 * @throws NullPointerException if {@code name} is {@code null}. 746 * @throws ModelException if searching fails. 747 * 748 * @see #getClassLoader() 749 */ 750 public URL findResource( final String name ) throws ModelException 751 { 752 if ( name == null ) 753 { 754 throw new NullPointerException( "name" ); 755 } 756 757 final long t0 = System.currentTimeMillis(); 758 final URL resource = this.getClassLoader() == null 759 ? ClassLoader.getSystemResource( name ) 760 : this.getClassLoader().getResource( name ); 761 762 if ( this.isLoggable( Level.FINE ) ) 763 { 764 this.log( Level.FINE, getMessage( "resourcesReport", name, System.currentTimeMillis() - t0 ), null ); 765 } 766 767 return resource; 768 } 769 770 /** 771 * Searches the context for resources with a given name. 772 * 773 * @param name The name of the resources to search. 774 * 775 * @return An enumeration of URL objects for reading the resources. If no resources are found, the enumeration will 776 * be empty. 777 * 778 * @throws NullPointerException if {@code name} is {@code null}. 779 * @throws ModelException if searching fails. 780 * 781 * @see #getClassLoader() 782 */ 783 public Enumeration<URL> findResources( final String name ) throws ModelException 784 { 785 if ( name == null ) 786 { 787 throw new NullPointerException( "name" ); 788 } 789 790 try 791 { 792 final long t0 = System.currentTimeMillis(); 793 final Enumeration<URL> resources = this.getClassLoader() == null 794 ? ClassLoader.getSystemResources( name ) 795 : this.getClassLoader().getResources( name ); 796 797 if ( this.isLoggable( Level.FINE ) ) 798 { 799 this.log( Level.FINE, getMessage( "resourcesReport", name, System.currentTimeMillis() - t0 ), null ); 800 } 801 802 return resources; 803 } 804 catch ( final IOException e ) 805 { 806 throw new ModelException( getMessage( e ), e ); 807 } 808 } 809 810 /** 811 * Searches the context for {@code Modlets}. 812 * 813 * @return The {@code Modlets} found in the context or {@code null}. 814 * 815 * @throws ModelException if searching {@code Modlets} fails. 816 * 817 * @see ModletProvider META-INF/services/org.jomc.modlet.ModletProvider 818 * @see #getModlets() 819 * @deprecated As of JOMC 1.6, replaced by {@link #findModlets(org.jomc.modlet.Modlets)}. This method will be 820 * removed in JOMC 2.0. 821 */ 822 @Deprecated 823 public abstract Modlets findModlets() throws ModelException; 824 825 /** 826 * Searches the context for {@code Modlets}. 827 * 828 * @param modlets The {@code Modlets} currently being searched. 829 * 830 * @return The {@code Modlets} found in the context or {@code null}. 831 * 832 * @throws NullPointerException if {@code modlets} is {@code null}. 833 * @throws ModelException if searching {@code Modlets} fails. 834 * 835 * @see ModletProvider META-INF/services/org.jomc.modlet.ModletProvider 836 * @see #getModlets() 837 * @since 1.6 838 */ 839 public abstract Modlets findModlets( Modlets modlets ) throws ModelException; 840 841 /** 842 * Processes a list of {@code Modlet}s. 843 * 844 * @param modlets The {@code Modlets} currently being processed. 845 * 846 * @return The processed {@code Modlets} or {@code null}. 847 * 848 * @throws NullPointerException if {@code modlets} is {@code null}. 849 * @throws ModelException if processing {@code Modlets} fails. 850 * 851 * @see ModletProcessor META-INF/services/org.jomc.modlet.ModletProcessor 852 * @see #getModlets() 853 * @since 1.6 854 */ 855 public abstract Modlets processModlets( Modlets modlets ) throws ModelException; 856 857 /** 858 * Validates a list of {@code Modlet}s. 859 * 860 * @param modlets The {@code Modlets} to validate. 861 * 862 * @return Validation report. 863 * 864 * @throws NullPointerException if {@code modlets} is {@code null}. 865 * @throws ModelException if validating {@code modlets} fails. 866 * 867 * @see ModletValidator META-INF/services/org.jomc.modlet.ModletValidator 868 * @see #getModlets() 869 * @since 1.9 870 */ 871 public abstract ModelValidationReport validateModlets( Modlets modlets ) throws ModelException; 872 873 /** 874 * Creates a new {@code Model} instance. 875 * 876 * @param model The identifier of the {@code Model} to create. 877 * 878 * @return A new instance of the {@code Model} identified by {@code model}. 879 * 880 * @throws NullPointerException if {@code model} is {@code null}. 881 * @throws ModelException if creating a new {@code Model} instance fails. 882 * 883 * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProvider.class.getName(), ModelProvider.class ) 884 * @see ModletObject#MODEL_PUBLIC_ID 885 */ 886 public abstract Model findModel( String model ) throws ModelException; 887 888 /** 889 * Populates a given {@code Model} instance. 890 * 891 * @param model The {@code Model} to populate. 892 * 893 * @return The populated model. 894 * 895 * @throws NullPointerException if {@code model} is {@code null}. 896 * @throws ModelException if populating {@code model} fails. 897 * 898 * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProvider.class.getName(), ModelProvider.class ) 899 * 900 * @since 1.2 901 */ 902 public abstract Model findModel( Model model ) throws ModelException; 903 904 /** 905 * Gets the name of the class providing the default {@code ModelContext} implementation. 906 * <p> 907 * The name of the class providing the default {@code ModelContext} implementation returned by method 908 * {@link #createModelContext(java.lang.ClassLoader)} is controlled by system property 909 * {@code org.jomc.modlet.ModelContext.className}. If that property is not set, the name of the 910 * {@link org.jomc.modlet.DefaultModelContext} class is returned. 911 * </p> 912 * 913 * @return The name of the class providing the default {@code ModelContext} implementation. 914 * 915 * @see #setModelContextClassName(java.lang.String) 916 * 917 * @deprecated As of JOMC 1.2, replaced by class {@link ModelContextFactory}. This method will be removed in version 918 * 2.0. 919 */ 920 @Deprecated 921 public static String getModelContextClassName() 922 { 923 if ( modelContextClassName == null ) 924 { 925 modelContextClassName = System.getProperty( "org.jomc.modlet.ModelContext.className", 926 DefaultModelContext.class.getName() ); 927 928 } 929 930 return modelContextClassName; 931 } 932 933 /** 934 * Sets the name of the class providing the default {@code ModelContext} implementation. 935 * 936 * @param value The new name of the class providing the default {@code ModelContext} implementation or {@code null}. 937 * 938 * @see #getModelContextClassName() 939 * 940 * @deprecated As of JOMC 1.2, replaced by class {@link ModelContextFactory}. This method will be removed in version 941 * 2.0. 942 */ 943 @Deprecated 944 public static void setModelContextClassName( final String value ) 945 { 946 modelContextClassName = value; 947 } 948 949 /** 950 * Creates a new default {@code ModelContext} instance. 951 * 952 * @param classLoader The class loader to create a new default {@code ModelContext} instance with or {@code null}, 953 * to create a new context using the platform's bootstrap class loader. 954 * 955 * @return A new {@code ModelContext} instance. 956 * 957 * @throws ModelException if creating a new {@code ModelContext} instance fails. 958 * 959 * @see #getModelContextClassName() 960 * 961 * @deprecated As of JOMC 1.2, replaced by method {@link ModelContextFactory#newModelContext(java.lang.ClassLoader)}. 962 * This method will be removed in version 2.0. 963 */ 964 public static ModelContext createModelContext( final ClassLoader classLoader ) throws ModelException 965 { 966 if ( getModelContextClassName().equals( DefaultModelContext.class.getName() ) ) 967 { 968 return new DefaultModelContext( classLoader ); 969 } 970 971 try 972 { 973 final Class<?> clazz = Class.forName( getModelContextClassName(), false, classLoader ); 974 975 if ( !ModelContext.class.isAssignableFrom( clazz ) ) 976 { 977 throw new ModelException( getMessage( "illegalContextImplementation", getModelContextClassName(), 978 ModelContext.class.getName() ) ); 979 980 } 981 982 final Constructor<? extends ModelContext> ctor = 983 clazz.asSubclass( ModelContext.class ).getDeclaredConstructor( ClassLoader.class ); 984 985 return ctor.newInstance( classLoader ); 986 } 987 catch ( final ClassNotFoundException e ) 988 { 989 throw new ModelException( getMessage( "contextClassNotFound", getModelContextClassName() ), e ); 990 } 991 catch ( final NoSuchMethodException e ) 992 { 993 throw new ModelException( getMessage( "contextConstructorNotFound", getModelContextClassName() ), e ); 994 } 995 catch ( final InstantiationException e ) 996 { 997 final String message = getMessage( e ); 998 throw new ModelException( getMessage( "contextInstantiationException", getModelContextClassName(), 999 message != null ? " " + message : "" ), e ); 1000 1001 } 1002 catch ( final IllegalAccessException e ) 1003 { 1004 final String message = getMessage( e ); 1005 throw new ModelException( getMessage( "contextConstructorAccessDenied", getModelContextClassName(), 1006 message != null ? " " + message : "" ), e ); 1007 1008 } 1009 catch ( final InvocationTargetException e ) 1010 { 1011 String message = getMessage( e ); 1012 if ( message == null && e.getTargetException() != null ) 1013 { 1014 message = getMessage( e.getTargetException() ); 1015 } 1016 1017 throw new ModelException( getMessage( "contextConstructorException", getModelContextClassName(), 1018 message != null ? " " + message : "" ), e ); 1019 1020 } 1021 } 1022 1023 /** 1024 * Processes a {@code Model}. 1025 * 1026 * @param model The {@code Model} to process. 1027 * 1028 * @return The processed {@code Model}. 1029 * 1030 * @throws NullPointerException if {@code model} is {@code null}. 1031 * @throws ModelException if processing {@code model} fails. 1032 * 1033 * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProcessor.class.getName(), ModelProcessor.class ) 1034 */ 1035 public abstract Model processModel( Model model ) throws ModelException; 1036 1037 /** 1038 * Validates a given {@code Model}. 1039 * 1040 * @param model The {@code Model} to validate. 1041 * 1042 * @return Validation report. 1043 * 1044 * @throws NullPointerException if {@code model} is {@code null}. 1045 * @throws ModelException if validating {@code model} fails. 1046 * 1047 * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelValidator.class.getName(), ModelValidator.class ) 1048 * @see ModelValidationReport#isModelValid() 1049 */ 1050 public abstract ModelValidationReport validateModel( Model model ) throws ModelException; 1051 1052 /** 1053 * Validates a given model. 1054 * 1055 * @param model The identifier of the {@code Model} to use for validating {@code source}. 1056 * @param source A source providing the model to validate. 1057 * 1058 * @return Validation report. 1059 * 1060 * @throws NullPointerException if {@code model} or {@code source} is {@code null}. 1061 * @throws ModelException if validating the model fails. 1062 * 1063 * @see #createSchema(java.lang.String) 1064 * @see ModelValidationReport#isModelValid() 1065 * @see ModletObject#MODEL_PUBLIC_ID 1066 */ 1067 public abstract ModelValidationReport validateModel( String model, Source source ) throws ModelException; 1068 1069 /** 1070 * Creates a new SAX entity resolver instance of a given model. 1071 * 1072 * @param model The identifier of the model to create a new SAX entity resolver of. 1073 * 1074 * @return A new SAX entity resolver instance of the model identified by {@code model}. 1075 * 1076 * @throws NullPointerException if {@code model} is {@code null}. 1077 * @throws ModelException if creating a new SAX entity resolver instance fails. 1078 * 1079 * @see ModletObject#MODEL_PUBLIC_ID 1080 */ 1081 public abstract EntityResolver createEntityResolver( String model ) throws ModelException; 1082 1083 /** 1084 * Creates a new SAX entity resolver instance for a given public identifier URI. 1085 * 1086 * @param publicId The public identifier URI to create a new SAX entity resolver for. 1087 * 1088 * @return A new SAX entity resolver instance for the public identifier URI {@code publicId}. 1089 * 1090 * @throws NullPointerException if {@code publicId} is {@code null}. 1091 * @throws ModelException if creating a new SAX entity resolver instance fails. 1092 * 1093 * @see ModletObject#PUBLIC_ID 1094 * @since 1.2 1095 * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0. 1096 */ 1097 @Deprecated 1098 public abstract EntityResolver createEntityResolver( URI publicId ) throws ModelException; 1099 1100 /** 1101 * Creates a new L/S resource resolver instance of a given model. 1102 * 1103 * @param model The identifier of the model to create a new L/S resource resolver of. 1104 * 1105 * @return A new L/S resource resolver instance of the model identified by {@code model}. 1106 * 1107 * @throws NullPointerException if {@code model} is {@code null}. 1108 * @throws ModelException if creating a new L/S resource resolver instance fails. 1109 * 1110 * @see ModletObject#MODEL_PUBLIC_ID 1111 */ 1112 public abstract LSResourceResolver createResourceResolver( String model ) throws ModelException; 1113 1114 /** 1115 * Creates a new L/S resource resolver instance for a given public identifier URI. 1116 * 1117 * @param publicId The public identifier URI to create a new L/S resource resolver for. 1118 * 1119 * @return A new L/S resource resolver instance for the public identifier URI {@code publicId}. 1120 * 1121 * @throws NullPointerException if {@code publicId} is {@code null}. 1122 * @throws ModelException if creating a new L/S resource resolver instance fails. 1123 * 1124 * @see ModletObject#PUBLIC_ID 1125 * @since 1.2 1126 * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0. 1127 */ 1128 @Deprecated 1129 public abstract LSResourceResolver createResourceResolver( URI publicId ) throws ModelException; 1130 1131 /** 1132 * Creates a new JAXP schema instance of a given model. 1133 * 1134 * @param model The identifier of the model to create a new JAXP schema instance of. 1135 * 1136 * @return A new JAXP schema instance of the model identified by {@code model}. 1137 * 1138 * @throws NullPointerException if {@code model} is {@code null}. 1139 * @throws ModelException if creating a new JAXP schema instance fails. 1140 * 1141 * @see ModletObject#MODEL_PUBLIC_ID 1142 */ 1143 public abstract javax.xml.validation.Schema createSchema( String model ) throws ModelException; 1144 1145 /** 1146 * Creates a new JAXP schema instance for a given public identifier URI. 1147 * 1148 * @param publicId The public identifier URI to create a new JAXP schema instance for. 1149 * 1150 * @return A new JAXP schema instance for the public identifier URI {@code publicId}. 1151 * 1152 * @throws NullPointerException if {@code publicId} is {@code null}. 1153 * @throws ModelException if creating a new JAXP schema instance fails. 1154 * 1155 * @see ModletObject#PUBLIC_ID 1156 * @since 1.2 1157 * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0. 1158 */ 1159 @Deprecated 1160 public abstract javax.xml.validation.Schema createSchema( URI publicId ) throws ModelException; 1161 1162 /** 1163 * Creates a new JAXB context instance of a given model. 1164 * 1165 * @param model The identifier of the model to create a new JAXB context instance of. 1166 * 1167 * @return A new JAXB context instance of the model identified by {@code model}. 1168 * 1169 * @throws NullPointerException if {@code model} is {@code null}. 1170 * @throws ModelException if creating a new JAXB context instance fails. 1171 * 1172 * @see ModletObject#MODEL_PUBLIC_ID 1173 */ 1174 public abstract JAXBContext createContext( String model ) throws ModelException; 1175 1176 /** 1177 * Creates a new JAXB context instance for a given public identifier URI. 1178 * 1179 * @param publicId The public identifier URI to create a new JAXB context instance for. 1180 * 1181 * @return A new JAXB context instance for the public identifier URI {@code publicId}. 1182 * 1183 * @throws NullPointerException if {@code publicId} is {@code null}. 1184 * @throws ModelException if creating a new JAXB context instance fails. 1185 * 1186 * @see ModletObject#PUBLIC_ID 1187 * @since 1.2 1188 * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0. 1189 */ 1190 @Deprecated 1191 public abstract JAXBContext createContext( URI publicId ) throws ModelException; 1192 1193 /** 1194 * Creates a new JAXB marshaller instance of a given model. 1195 * 1196 * @param model The identifier of the model to create a new JAXB marshaller instance of. 1197 * 1198 * @return A new JAXB marshaller instance of the model identified by {@code model}. 1199 * 1200 * @throws NullPointerException if {@code model} is {@code null}. 1201 * @throws ModelException if creating a new JAXB marshaller instance fails. 1202 * 1203 * @see ModletObject#MODEL_PUBLIC_ID 1204 */ 1205 public abstract Marshaller createMarshaller( String model ) throws ModelException; 1206 1207 /** 1208 * Creates a new JAXB marshaller instance for a given public identifier URI. 1209 * 1210 * @param publicId The public identifier URI to create a new JAXB marshaller instance for. 1211 * 1212 * @return A new JAXB marshaller instance for the public identifier URI {@code publicId}. 1213 * 1214 * @throws NullPointerException if {@code publicId} is {@code null}. 1215 * @throws ModelException if creating a new JAXB marshaller instance fails. 1216 * 1217 * @see ModletObject#PUBLIC_ID 1218 * @since 1.2 1219 * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0. 1220 */ 1221 @Deprecated 1222 public abstract Marshaller createMarshaller( URI publicId ) throws ModelException; 1223 1224 /** 1225 * Creates a new JAXB unmarshaller instance of a given model. 1226 * 1227 * @param model The identifier of the model to create a new JAXB unmarshaller instance of. 1228 * 1229 * @return A new JAXB unmarshaller instance of the model identified by {@code model}. 1230 * 1231 * @throws NullPointerException if {@code model} is {@code null}. 1232 * @throws ModelException if creating a new JAXB unmarshaller instance fails. 1233 * 1234 * @see ModletObject#MODEL_PUBLIC_ID 1235 */ 1236 public abstract Unmarshaller createUnmarshaller( String model ) throws ModelException; 1237 1238 /** 1239 * Creates a new JAXB unmarshaller instance for a given given public identifier URI. 1240 * 1241 * @param publicId The public identifier URI to create a new JAXB unmarshaller instance for. 1242 * 1243 * @return A new JAXB unmarshaller instance for the public identifier URI {@code publicId}. 1244 * 1245 * @throws NullPointerException if {@code publicId} is {@code null}. 1246 * @throws ModelException if creating a new JAXB unmarshaller instance fails. 1247 * 1248 * @see ModletObject#PUBLIC_ID 1249 * @since 1.2 1250 * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0. 1251 */ 1252 @Deprecated 1253 public abstract Unmarshaller createUnmarshaller( URI publicId ) throws ModelException; 1254 1255 /** 1256 * Creates service objects of a model. 1257 * 1258 * @param <T> The type of the service. 1259 * @param model The identifier of the {@code Model} to create service objects of. 1260 * @param service The identifier of the service to create objects of. 1261 * @param type The class of the type of the service. 1262 * 1263 * @return An ordered, unmodifiable collection of new service objects identified by {@code service} of the model 1264 * identified by {@code model}. 1265 * 1266 * @throws NullPointerException if {@code model}, {@code service} or {@code type} is {@code null}. 1267 * @throws ModelException if creating service objects fails. 1268 * 1269 * @see ModelProvider 1270 * @see ModelProcessor 1271 * @see ModelValidator 1272 * 1273 * @since 1.9 1274 */ 1275 public abstract <T> Collection<? extends T> createServiceObjects( final String model, final String service, 1276 final Class<T> type ) 1277 throws ModelException; 1278 1279 /** 1280 * Creates a new service object. 1281 * 1282 * @param <T> The type of the service. 1283 * @param service The service to create a new object of. 1284 * @param type The class of the type of the service. 1285 * 1286 * @return An new service object for {@code service}. 1287 * 1288 * @throws NullPointerException if {@code service} or {@code type} is {@code null}. 1289 * @throws ModelException if creating the service object fails. 1290 * 1291 * @see ModletProvider 1292 * @see ModletProcessor 1293 * @see ModletValidator 1294 * @see ServiceFactory 1295 * 1296 * @since 1.2 1297 * @deprecated As of JOMC 1.9, please use method {@link #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class)}. 1298 * This method will be removed in JOMC 2.0. 1299 */ 1300 @Deprecated 1301 public abstract <T> T createServiceObject( final Service service, final Class<T> type ) throws ModelException; 1302 1303 private static String getMessage( final String key, final Object... args ) 1304 { 1305 return MessageFormat.format( ResourceBundle.getBundle( 1306 ModelContext.class.getName().replace( '.', '/' ), Locale.getDefault() ).getString( key ), args ); 1307 1308 } 1309 1310 private static String getMessage( final Throwable t ) 1311 { 1312 return t != null 1313 ? t.getMessage() != null && t.getMessage().trim().length() > 0 1314 ? t.getMessage() 1315 : getMessage( t.getCause() ) 1316 : null; 1317 1318 } 1319 1320 }