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