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