ModelContext.java

  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. import java.io.IOException;
  33. import java.lang.reflect.Constructor;
  34. import java.lang.reflect.InvocationTargetException;
  35. import java.net.URI;
  36. import java.net.URL;
  37. import java.text.MessageFormat;
  38. import java.util.Collection;
  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.Marshaller;
  51. import javax.xml.bind.Unmarshaller;
  52. import javax.xml.transform.Source;
  53. import org.w3c.dom.ls.LSResourceResolver;
  54. import org.xml.sax.EntityResolver;

  55. /**
  56.  * Model context interface.
  57.  * <p>
  58.  * <b>Use Cases:</b><br/><ul>
  59.  * <li>{@link #createContext(java.lang.String) }</li>
  60.  * <li>{@link #createEntityResolver(java.lang.String) }</li>
  61.  * <li>{@link #createMarshaller(java.lang.String) }</li>
  62.  * <li>{@link #createResourceResolver(java.lang.String) }</li>
  63.  * <li>{@link #createSchema(java.lang.String) }</li>
  64.  * <li>{@link #createUnmarshaller(java.lang.String) }</li>
  65.  * <li>{@link #findModel(java.lang.String) }</li>
  66.  * <li>{@link #findModel(org.jomc.modlet.Model) }</li>
  67.  * <li>{@link #processModel(org.jomc.modlet.Model) }</li>
  68.  * <li>{@link #validateModel(org.jomc.modlet.Model) }</li>
  69.  * <li>{@link #validateModel(java.lang.String, javax.xml.transform.Source) }</li>
  70.  * </ul>
  71.  *
  72.  * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
  73.  * @version $JOMC: ModelContext.java 5051 2015-05-30 17:29:32Z schulte $
  74.  *
  75.  * @see ModelContextFactory
  76.  */
  77. public abstract class ModelContext
  78. {

  79.     /**
  80.      * Listener interface.
  81.      */
  82.     public abstract static class Listener
  83.     {

  84.         /**
  85.          * Creates a new {@code Listener} instance.
  86.          */
  87.         public Listener()
  88.         {
  89.             super();
  90.         }

  91.         /**
  92.          * Gets called on logging.
  93.          *
  94.          * @param level The level of the event.
  95.          * @param message The message of the event or {@code null}.
  96.          * @param t The throwable of the event or {@code null}.
  97.          *
  98.          * @throws NullPointerException if {@code level} is {@code null}.
  99.          */
  100.         public void onLog( final Level level, final String message, final Throwable t )
  101.         {
  102.             if ( level == null )
  103.             {
  104.                 throw new NullPointerException( "level" );
  105.             }
  106.         }

  107.     }

  108.     /**
  109.      * Default {@code http://jomc.org/modlet} namespace schema system id.
  110.      *
  111.      * @see #getDefaultModletSchemaSystemId()
  112.      */
  113.     private static final String DEFAULT_MODLET_SCHEMA_SYSTEM_ID =
  114.         "http://xml.jomc.org/modlet/jomc-modlet-1.9.xsd";

  115.     /**
  116.      * Log level events are logged at by default.
  117.      *
  118.      * @see #getDefaultLogLevel()
  119.      */
  120.     private static final Level DEFAULT_LOG_LEVEL = Level.WARNING;

  121.     /**
  122.      * Default log level.
  123.      */
  124.     private static volatile Level defaultLogLevel;

  125.     /**
  126.      * Default {@code http://jomc.org/model/modlet} namespace schema system id.
  127.      */
  128.     private static volatile String defaultModletSchemaSystemId;

  129.     /**
  130.      * Class name of the {@code ModelContext} implementation.
  131.      */
  132.     @Deprecated
  133.     private static volatile String modelContextClassName;

  134.     /**
  135.      * The attributes of the instance.
  136.      */
  137.     private final Map<String, Object> attributes = new HashMap<String, Object>();

  138.     /**
  139.      * The class loader of the instance.
  140.      */
  141.     private ClassLoader classLoader;

  142.     /**
  143.      * Flag indicating the {@code classLoader} field is initialized.
  144.      *
  145.      * @since 1.2
  146.      */
  147.     private boolean classLoaderSet;

  148.     /**
  149.      * The listeners of the instance.
  150.      */
  151.     private List<Listener> listeners;

  152.     /**
  153.      * Log level of the instance.
  154.      */
  155.     private Level logLevel;

  156.     /**
  157.      * The {@code Modlets} of the instance.
  158.      */
  159.     private Modlets modlets;

  160.     /**
  161.      * Modlet namespace schema system id of the instance.
  162.      */
  163.     private String modletSchemaSystemId;

  164.     /**
  165.      * Creates a new {@code ModelContext} instance.
  166.      *
  167.      * @since 1.2
  168.      */
  169.     public ModelContext()
  170.     {
  171.         super();
  172.         this.classLoader = null;
  173.         this.classLoaderSet = false;
  174.     }

  175.     /**
  176.      * Creates a new {@code ModelContext} instance taking a class loader.
  177.      *
  178.      * @param classLoader The class loader of the context.
  179.      *
  180.      * @see #getClassLoader()
  181.      */
  182.     public ModelContext( final ClassLoader classLoader )
  183.     {
  184.         super();
  185.         this.classLoader = classLoader;
  186.         this.classLoaderSet = true;
  187.     }

  188.     /**
  189.      * Gets a set holding the names of all attributes of the context.
  190.      *
  191.      * @return An unmodifiable set holding the names of all attributes of the context.
  192.      *
  193.      * @see #clearAttribute(java.lang.String)
  194.      * @see #getAttribute(java.lang.String)
  195.      * @see #getAttribute(java.lang.String, java.lang.Object)
  196.      * @see #setAttribute(java.lang.String, java.lang.Object)
  197.      * @since 1.2
  198.      */
  199.     public Set<String> getAttributeNames()
  200.     {
  201.         return Collections.unmodifiableSet( this.attributes.keySet() );
  202.     }

  203.     /**
  204.      * Gets an attribute of the context.
  205.      *
  206.      * @param name The name of the attribute to get.
  207.      *
  208.      * @return The value of the attribute with name {@code name}; {@code null} if no attribute matching {@code name} is
  209.      * found.
  210.      *
  211.      * @throws NullPointerException if {@code name} is {@code null}.
  212.      *
  213.      * @see #getAttribute(java.lang.String, java.lang.Object)
  214.      * @see #setAttribute(java.lang.String, java.lang.Object)
  215.      * @see #clearAttribute(java.lang.String)
  216.      */
  217.     public Object getAttribute( final String name )
  218.     {
  219.         if ( name == null )
  220.         {
  221.             throw new NullPointerException( "name" );
  222.         }

  223.         return this.attributes.get( name );
  224.     }

  225.     /**
  226.      * Gets an attribute of the context.
  227.      *
  228.      * @param name The name of the attribute to get.
  229.      * @param def The value to return if no attribute matching {@code name} is found.
  230.      *
  231.      * @return The value of the attribute with name {@code name}; {@code def} if no such attribute is found.
  232.      *
  233.      * @throws NullPointerException if {@code name} is {@code null}.
  234.      *
  235.      * @see #getAttribute(java.lang.String)
  236.      * @see #setAttribute(java.lang.String, java.lang.Object)
  237.      * @see #clearAttribute(java.lang.String)
  238.      */
  239.     public Object getAttribute( final String name, final Object def )
  240.     {
  241.         if ( name == null )
  242.         {
  243.             throw new NullPointerException( "name" );
  244.         }

  245.         Object value = this.getAttribute( name );

  246.         if ( value == null )
  247.         {
  248.             value = def;
  249.         }

  250.         return value;
  251.     }

  252.     /**
  253.      * Sets an attribute in the context.
  254.      *
  255.      * @param name The name of the attribute to set.
  256.      * @param value The value of the attribute to set.
  257.      *
  258.      * @return The previous value of the attribute with name {@code name}; {@code null} if no such value is found.
  259.      *
  260.      * @throws NullPointerException if {@code name} or {@code value} is {@code null}.
  261.      *
  262.      * @see #getAttribute(java.lang.String)
  263.      * @see #getAttribute(java.lang.String, java.lang.Object)
  264.      * @see #clearAttribute(java.lang.String)
  265.      */
  266.     public Object setAttribute( final String name, final Object value )
  267.     {
  268.         if ( name == null )
  269.         {
  270.             throw new NullPointerException( "name" );
  271.         }
  272.         if ( value == null )
  273.         {
  274.             throw new NullPointerException( "value" );
  275.         }

  276.         return this.attributes.put( name, value );
  277.     }

  278.     /**
  279.      * Removes an attribute from the context.
  280.      *
  281.      * @param name The name of the attribute to remove.
  282.      *
  283.      * @throws NullPointerException if {@code name} is {@code null}.
  284.      *
  285.      * @see #getAttribute(java.lang.String)
  286.      * @see #getAttribute(java.lang.String, java.lang.Object)
  287.      * @see #setAttribute(java.lang.String, java.lang.Object)
  288.      */
  289.     public void clearAttribute( final String name )
  290.     {
  291.         if ( name == null )
  292.         {
  293.             throw new NullPointerException( "name" );
  294.         }

  295.         this.attributes.remove( name );
  296.     }

  297.     /**
  298.      * Gets the class loader of the context.
  299.      *
  300.      * @return The class loader of the context or {@code null}, indicating the bootstrap class loader.
  301.      *
  302.      * @see #findClass(java.lang.String)
  303.      * @see #findResource(java.lang.String)
  304.      * @see #findResources(java.lang.String)
  305.      */
  306.     public ClassLoader getClassLoader()
  307.     {
  308.         if ( !this.classLoaderSet )
  309.         {
  310.             this.classLoader = this.getClass().getClassLoader();
  311.             this.classLoaderSet = true;
  312.         }

  313.         return this.classLoader;
  314.     }

  315.     /**
  316.      * Gets the listeners of the context.
  317.      * <p>
  318.      * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
  319.      * to the returned list will be present inside the object. This is why there is no {@code set} method for the
  320.      * listeners property.
  321.      * </p>
  322.      *
  323.      * @return The list of listeners of the context.
  324.      *
  325.      * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
  326.      */
  327.     public List<Listener> getListeners()
  328.     {
  329.         if ( this.listeners == null )
  330.         {
  331.             this.listeners = new LinkedList<Listener>();
  332.         }

  333.         return this.listeners;
  334.     }

  335.     /**
  336.      * Gets the default {@code http://jomc.org/modlet} namespace schema system id.
  337.      * <p>
  338.      * The default {@code http://jomc.org/modlet} namespace schema system id is controlled by system property
  339.      * {@code org.jomc.modlet.ModelContext.defaultModletSchemaSystemId} holding a system id URI.
  340.      * If that property is not set, the {@code http://xml.jomc.org/modlet/jomc-modlet-1.9.xsd} default is
  341.      * returned.
  342.      * </p>
  343.      *
  344.      * @return The default system id of the {@code http://jomc.org/modlet} namespace schema.
  345.      *
  346.      * @see #setDefaultModletSchemaSystemId(java.lang.String)
  347.      */
  348.     public static String getDefaultModletSchemaSystemId()
  349.     {
  350.         if ( defaultModletSchemaSystemId == null )
  351.         {
  352.             defaultModletSchemaSystemId = System.getProperty(
  353.                 "org.jomc.modlet.ModelContext.defaultModletSchemaSystemId", DEFAULT_MODLET_SCHEMA_SYSTEM_ID );

  354.         }

  355.         return defaultModletSchemaSystemId;
  356.     }

  357.     /**
  358.      * Sets the default {@code http://jomc.org/modlet} namespace schema system id.
  359.      *
  360.      * @param value The new default {@code http://jomc.org/modlet} namespace schema system id or {@code null}.
  361.      *
  362.      * @see #getDefaultModletSchemaSystemId()
  363.      */
  364.     public static void setDefaultModletSchemaSystemId( final String value )
  365.     {
  366.         defaultModletSchemaSystemId = value;
  367.     }

  368.     /**
  369.      * Gets the {@code http://jomc.org/modlet} namespace schema system id of the context.
  370.      *
  371.      * @return The {@code http://jomc.org/modlet} namespace schema system id of the context.
  372.      *
  373.      * @see #getDefaultModletSchemaSystemId()
  374.      * @see #setModletSchemaSystemId(java.lang.String)
  375.      */
  376.     public final String getModletSchemaSystemId()
  377.     {
  378.         if ( this.modletSchemaSystemId == null )
  379.         {
  380.             this.modletSchemaSystemId = getDefaultModletSchemaSystemId();

  381.             if ( this.isLoggable( Level.CONFIG ) )
  382.             {
  383.                 this.log( Level.CONFIG,
  384.                           getMessage( "defaultModletSchemaSystemIdInfo", this.modletSchemaSystemId ), null );

  385.             }
  386.         }

  387.         return this.modletSchemaSystemId;
  388.     }

  389.     /**
  390.      * Sets the {@code http://jomc.org/modlet} namespace schema system id of the context.
  391.      *
  392.      * @param value The new {@code http://jomc.org/modlet} namespace schema system id or {@code null}.
  393.      *
  394.      * @see #getModletSchemaSystemId()
  395.      */
  396.     public final void setModletSchemaSystemId( final String value )
  397.     {
  398.         final String oldModletSchemaSystemId = this.getModletSchemaSystemId();
  399.         this.modletSchemaSystemId = value;

  400.         if ( this.modlets != null )
  401.         {
  402.             for ( int i = 0, s0 = this.modlets.getModlet().size(); i < s0; i++ )
  403.             {
  404.                 final Modlet m = this.modlets.getModlet().get( i );

  405.                 if ( m.getSchemas() != null )
  406.                 {
  407.                     final Schema s = m.getSchemas().getSchemaBySystemId( oldModletSchemaSystemId );

  408.                     if ( s != null )
  409.                     {
  410.                         s.setSystemId( value );
  411.                     }
  412.                 }
  413.             }
  414.         }
  415.     }

  416.     /**
  417.      * Gets the default log level events are logged at.
  418.      * <p>
  419.      * The default log level is controlled by system property
  420.      * {@code org.jomc.modlet.ModelContext.defaultLogLevel} holding the log level to log events at by default.
  421.      * If that property is not set, the {@code WARNING} default is returned.
  422.      * </p>
  423.      *
  424.      * @return The log level events are logged at by default.
  425.      *
  426.      * @see #getLogLevel()
  427.      * @see Level#parse(java.lang.String)
  428.      */
  429.     public static Level getDefaultLogLevel()
  430.     {
  431.         if ( defaultLogLevel == null )
  432.         {
  433.             defaultLogLevel = Level.parse( System.getProperty(
  434.                 "org.jomc.modlet.ModelContext.defaultLogLevel", DEFAULT_LOG_LEVEL.getName() ) );

  435.         }

  436.         return defaultLogLevel;
  437.     }

  438.     /**
  439.      * Sets the default log level events are logged at.
  440.      *
  441.      * @param value The new default level events are logged at or {@code null}.
  442.      *
  443.      * @see #getDefaultLogLevel()
  444.      */
  445.     public static void setDefaultLogLevel( final Level value )
  446.     {
  447.         defaultLogLevel = value;
  448.     }

  449.     /**
  450.      * Gets the log level of the context.
  451.      *
  452.      * @return The log level of the context.
  453.      *
  454.      * @see #getDefaultLogLevel()
  455.      * @see #setLogLevel(java.util.logging.Level)
  456.      * @see #isLoggable(java.util.logging.Level)
  457.      */
  458.     public final Level getLogLevel()
  459.     {
  460.         if ( this.logLevel == null )
  461.         {
  462.             this.logLevel = getDefaultLogLevel();

  463.             if ( this.isLoggable( Level.CONFIG ) )
  464.             {
  465.                 this.log( Level.CONFIG, getMessage( "defaultLogLevelInfo", this.logLevel.getLocalizedName() ), null );
  466.             }
  467.         }

  468.         return this.logLevel;
  469.     }

  470.     /**
  471.      * Sets the log level of the context.
  472.      *
  473.      * @param value The new log level of the context or {@code null}.
  474.      *
  475.      * @see #getLogLevel()
  476.      * @see #isLoggable(java.util.logging.Level)
  477.      */
  478.     public final void setLogLevel( final Level value )
  479.     {
  480.         this.logLevel = value;
  481.     }

  482.     /**
  483.      * Checks if a message at a given level is provided to the listeners of the context.
  484.      *
  485.      * @param level The level to test.
  486.      *
  487.      * @return {@code true}, if messages at {@code level} are provided to the listeners of the context; {@code false},
  488.      * if messages at {@code level} are not provided to the listeners of the context.
  489.      *
  490.      * @throws NullPointerException if {@code level} is {@code null}.
  491.      *
  492.      * @see #getLogLevel()
  493.      * @see #setLogLevel(java.util.logging.Level)
  494.      */
  495.     public boolean isLoggable( final Level level )
  496.     {
  497.         if ( level == null )
  498.         {
  499.             throw new NullPointerException( "level" );
  500.         }

  501.         return level.intValue() >= this.getLogLevel().intValue();
  502.     }

  503.     /**
  504.      * Notifies all listeners of the context.
  505.      *
  506.      * @param level The level of the event.
  507.      * @param message The message of the event or {@code null}.
  508.      * @param throwable The throwable of the event {@code null}.
  509.      *
  510.      * @throws NullPointerException if {@code level} is {@code null}.
  511.      *
  512.      * @see #getListeners()
  513.      * @see #isLoggable(java.util.logging.Level)
  514.      */
  515.     public void log( final Level level, final String message, final Throwable throwable )
  516.     {
  517.         if ( level == null )
  518.         {
  519.             throw new NullPointerException( "level" );
  520.         }

  521.         if ( this.isLoggable( level ) )
  522.         {
  523.             for ( final Listener l : this.getListeners() )
  524.             {
  525.                 l.onLog( level, message, throwable );
  526.             }
  527.         }
  528.     }

  529.     /**
  530.      * Gets the {@code Modlets} of the context.
  531.      * <p>
  532.      * If no {@code Modlets} have been set using the {@code setModlets} method, this method calls the
  533.      * {@code findModlets} method and the {@code processModlets} method to initialize the {@code Modlets} of the
  534.      * context.
  535.      * </p>
  536.      * <p>
  537.      * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
  538.      * to the returned list will be present inside the object.
  539.      * </p>
  540.      *
  541.      * @return The {@code Modlets} of the context.
  542.      *
  543.      * @throws ModelException if getting the {@code Modlets} of the context fails.
  544.      *
  545.      * @see #setModlets(org.jomc.modlet.Modlets)
  546.      * @see #findModlets(org.jomc.modlet.Modlets)
  547.      * @see #processModlets(org.jomc.modlet.Modlets)
  548.      * @see #validateModlets(org.jomc.modlet.Modlets)
  549.      */
  550.     public final Modlets getModlets() throws ModelException
  551.     {
  552.         if ( this.modlets == null )
  553.         {
  554.             final Modlet modlet = new Modlet();
  555.             modlet.setModel( ModletObject.MODEL_PUBLIC_ID );
  556.             modlet.setName( getMessage( "projectName" ) );
  557.             modlet.setVendor( getMessage( "projectVendor" ) );
  558.             modlet.setVersion( getMessage( "projectVersion" ) );
  559.             modlet.setSchemas( new Schemas() );

  560.             final Schema schema = new Schema();
  561.             schema.setPublicId( ModletObject.MODEL_PUBLIC_ID );
  562.             schema.setSystemId( this.getModletSchemaSystemId() );
  563.             schema.setContextId( ModletObject.class.getPackage().getName() );
  564.             schema.setClasspathId( ModletObject.class.getPackage().getName().replace( '.', '/' )
  565.                                        + "/jomc-modlet-1.9.xsd" );

  566.             modlet.getSchemas().getSchema().add( schema );

  567.             this.modlets = new Modlets();
  568.             this.modlets.getModlet().add( modlet );

  569.             long t0 = System.currentTimeMillis();
  570.             final Modlets provided = this.findModlets( this.modlets );

  571.             if ( this.isLoggable( Level.FINE ) )
  572.             {
  573.                 this.log( Level.FINE, getMessage( "findModletsReport",
  574.                                                   provided != null ? provided.getModlet().size() : 0,
  575.                                                   System.currentTimeMillis() - t0 ), null );

  576.             }

  577.             if ( provided != null )
  578.             {
  579.                 this.modlets = provided;
  580.             }

  581.             t0 = System.currentTimeMillis();
  582.             final Modlets processed = this.processModlets( this.modlets );

  583.             if ( this.isLoggable( Level.FINE ) )
  584.             {
  585.                 this.log( Level.FINE, getMessage( "processModletsReport",
  586.                                                   processed != null ? processed.getModlet().size() : 0,
  587.                                                   System.currentTimeMillis() - t0 ), null );
  588.             }

  589.             if ( processed != null )
  590.             {
  591.                 this.modlets = processed;
  592.             }

  593.             t0 = System.currentTimeMillis();
  594.             final ModelValidationReport report = this.validateModlets( this.modlets );

  595.             if ( this.isLoggable( Level.FINE ) )
  596.             {
  597.                 this.log( Level.FINE, getMessage( "validateModletsReport",
  598.                                                   this.modlets.getModlet().size(),
  599.                                                   System.currentTimeMillis() - t0 ), null );
  600.             }

  601.             for ( final ModelValidationReport.Detail detail : report.getDetails() )
  602.             {
  603.                 if ( this.isLoggable( detail.getLevel() ) )
  604.                 {
  605.                     this.log( detail.getLevel(), detail.getMessage(), null );
  606.                 }
  607.             }

  608.             if ( !report.isModelValid() )
  609.             {
  610.                 this.modlets = null;
  611.                 throw new ModelException( getMessage( "invalidModlets" ) );
  612.             }
  613.         }

  614.         return this.modlets;
  615.     }

  616.     /**
  617.      * Sets the {@code Modlets} of the context.
  618.      *
  619.      * @param value The new {@code Modlets} of the context or {@code null}.
  620.      *
  621.      * @see #getModlets()
  622.      */
  623.     public final void setModlets( final Modlets value )
  624.     {
  625.         this.modlets = value;
  626.     }

  627.     /**
  628.      * Searches the context for a class with a given name.
  629.      *
  630.      * @param name The name of the class to search.
  631.      *
  632.      * @return A class object of the class with name {@code name} or {@code null}, if no such class is found.
  633.      *
  634.      * @throws NullPointerException if {@code name} is {@code null}.
  635.      * @throws ModelException if searching fails.
  636.      *
  637.      * @see #getClassLoader()
  638.      */
  639.     public Class<?> findClass( final String name ) throws ModelException
  640.     {
  641.         if ( name == null )
  642.         {
  643.             throw new NullPointerException( "name" );
  644.         }

  645.         try
  646.         {
  647.             return Class.forName( name, false, this.getClassLoader() );
  648.         }
  649.         catch ( final ClassNotFoundException e )
  650.         {
  651.             if ( this.isLoggable( Level.FINE ) )
  652.             {
  653.                 this.log( Level.FINE, getMessage( e ), e );
  654.             }

  655.             return null;
  656.         }
  657.     }

  658.     /**
  659.      * Searches the context for a resource with a given name.
  660.      *
  661.      * @param name The name of the resource to search.
  662.      *
  663.      * @return An URL object for reading the resource or {@code null}, if no such resource is found.
  664.      *
  665.      * @throws NullPointerException if {@code name} is {@code null}.
  666.      * @throws ModelException if searching fails.
  667.      *
  668.      * @see #getClassLoader()
  669.      */
  670.     public URL findResource( final String name ) throws ModelException
  671.     {
  672.         if ( name == null )
  673.         {
  674.             throw new NullPointerException( "name" );
  675.         }

  676.         final long t0 = System.currentTimeMillis();
  677.         final URL resource = this.getClassLoader() == null
  678.                                  ? ClassLoader.getSystemResource( name )
  679.                                  : this.getClassLoader().getResource( name );

  680.         if ( this.isLoggable( Level.FINE ) )
  681.         {
  682.             this.log( Level.FINE, getMessage( "resourcesReport", name, System.currentTimeMillis() - t0 ), null );
  683.         }

  684.         return resource;
  685.     }

  686.     /**
  687.      * Searches the context for resources with a given name.
  688.      *
  689.      * @param name The name of the resources to search.
  690.      *
  691.      * @return An enumeration of URL objects for reading the resources. If no resources are found, the enumeration will
  692.      * be empty.
  693.      *
  694.      * @throws NullPointerException if {@code name} is {@code null}.
  695.      * @throws ModelException if searching fails.
  696.      *
  697.      * @see #getClassLoader()
  698.      */
  699.     public Enumeration<URL> findResources( final String name ) throws ModelException
  700.     {
  701.         if ( name == null )
  702.         {
  703.             throw new NullPointerException( "name" );
  704.         }

  705.         try
  706.         {
  707.             final long t0 = System.currentTimeMillis();
  708.             final Enumeration<URL> resources = this.getClassLoader() == null
  709.                                                    ? ClassLoader.getSystemResources( name )
  710.                                                    : this.getClassLoader().getResources( name );

  711.             if ( this.isLoggable( Level.FINE ) )
  712.             {
  713.                 this.log( Level.FINE, getMessage( "resourcesReport", name, System.currentTimeMillis() - t0 ), null );
  714.             }

  715.             return resources;
  716.         }
  717.         catch ( final IOException e )
  718.         {
  719.             throw new ModelException( getMessage( e ), e );
  720.         }
  721.     }

  722.     /**
  723.      * Searches the context for {@code Modlets}.
  724.      *
  725.      * @return The {@code Modlets} found in the context or {@code null}.
  726.      *
  727.      * @throws ModelException if searching {@code Modlets} fails.
  728.      *
  729.      * @see ModletProvider META-INF/services/org.jomc.modlet.ModletProvider
  730.      * @see #getModlets()
  731.      * @deprecated As of JOMC 1.6, replaced by {@link #findModlets(org.jomc.modlet.Modlets)}. This method will be
  732.      * removed in JOMC 2.0.
  733.      */
  734.     @Deprecated
  735.     public abstract Modlets findModlets() throws ModelException;

  736.     /**
  737.      * Searches the context for {@code Modlets}.
  738.      *
  739.      * @param modlets The {@code Modlets} currently being searched.
  740.      *
  741.      * @return The {@code Modlets} found in the context or {@code null}.
  742.      *
  743.      * @throws NullPointerException if {@code modlets} is {@code null}.
  744.      * @throws ModelException if searching {@code Modlets} fails.
  745.      *
  746.      * @see ModletProvider META-INF/services/org.jomc.modlet.ModletProvider
  747.      * @see #getModlets()
  748.      * @since 1.6
  749.      */
  750.     public abstract Modlets findModlets( Modlets modlets ) throws ModelException;

  751.     /**
  752.      * Processes a list of {@code Modlet}s.
  753.      *
  754.      * @param modlets The {@code Modlets} currently being processed.
  755.      *
  756.      * @return The processed {@code Modlets} or {@code null}.
  757.      *
  758.      * @throws NullPointerException if {@code modlets} is {@code null}.
  759.      * @throws ModelException if processing {@code Modlets} fails.
  760.      *
  761.      * @see ModletProcessor META-INF/services/org.jomc.modlet.ModletProcessor
  762.      * @see #getModlets()
  763.      * @since 1.6
  764.      */
  765.     public abstract Modlets processModlets( Modlets modlets ) throws ModelException;

  766.     /**
  767.      * Validates a list of {@code Modlet}s.
  768.      *
  769.      * @param modlets The {@code Modlets} to validate.
  770.      *
  771.      * @return Validation report.
  772.      *
  773.      * @throws NullPointerException if {@code modlets} is {@code null}.
  774.      * @throws ModelException if validating {@code modlets} fails.
  775.      *
  776.      * @see ModletValidator META-INF/services/org.jomc.modlet.ModletValidator
  777.      * @see #getModlets()
  778.      * @since 1.9
  779.      */
  780.     public abstract ModelValidationReport validateModlets( Modlets modlets ) throws ModelException;

  781.     /**
  782.      * Creates a new {@code Model} instance.
  783.      *
  784.      * @param model The identifier of the {@code Model} to create.
  785.      *
  786.      * @return A new instance of the {@code Model} identified by {@code model}.
  787.      *
  788.      * @throws NullPointerException if {@code model} is {@code null}.
  789.      * @throws ModelException if creating a new {@code Model} instance fails.
  790.      *
  791.      * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProvider.class.getName(), ModelProvider.class )
  792.      * @see ModletObject#MODEL_PUBLIC_ID
  793.      */
  794.     public abstract Model findModel( String model ) throws ModelException;

  795.     /**
  796.      * Populates a given {@code Model} instance.
  797.      *
  798.      * @param model The {@code Model} to populate.
  799.      *
  800.      * @return The populated model.
  801.      *
  802.      * @throws NullPointerException if {@code model} is {@code null}.
  803.      * @throws ModelException if populating {@code model} fails.
  804.      *
  805.      * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProvider.class.getName(), ModelProvider.class )
  806.      *
  807.      * @since 1.2
  808.      */
  809.     public abstract Model findModel( Model model ) throws ModelException;

  810.     /**
  811.      * Gets the name of the class providing the default {@code ModelContext} implementation.
  812.      * <p>
  813.      * The name of the class providing the default {@code ModelContext} implementation returned by method
  814.      * {@link #createModelContext(java.lang.ClassLoader)} is controlled by system property
  815.      * {@code org.jomc.modlet.ModelContext.className}. If that property is not set, the name of the
  816.      * {@link org.jomc.modlet.DefaultModelContext} class is returned.
  817.      * </p>
  818.      *
  819.      * @return The name of the class providing the default {@code ModelContext} implementation.
  820.      *
  821.      * @see #setModelContextClassName(java.lang.String)
  822.      *
  823.      * @deprecated As of JOMC 1.2, replaced by class {@link ModelContextFactory}. This method will be removed in version
  824.      * 2.0.
  825.      */
  826.     @Deprecated
  827.     public static String getModelContextClassName()
  828.     {
  829.         if ( modelContextClassName == null )
  830.         {
  831.             modelContextClassName = System.getProperty( "org.jomc.modlet.ModelContext.className",
  832.                                                         DefaultModelContext.class.getName() );

  833.         }

  834.         return modelContextClassName;
  835.     }

  836.     /**
  837.      * Sets the name of the class providing the default {@code ModelContext} implementation.
  838.      *
  839.      * @param value The new name of the class providing the default {@code ModelContext} implementation or {@code null}.
  840.      *
  841.      * @see #getModelContextClassName()
  842.      *
  843.      * @deprecated As of JOMC 1.2, replaced by class {@link ModelContextFactory}. This method will be removed in version
  844.      * 2.0.
  845.      */
  846.     @Deprecated
  847.     public static void setModelContextClassName( final String value )
  848.     {
  849.         modelContextClassName = value;
  850.     }

  851.     /**
  852.      * Creates a new default {@code ModelContext} instance.
  853.      *
  854.      * @param classLoader The class loader to create a new default {@code ModelContext} instance with or {@code null},
  855.      * to create a new context using the platform's bootstrap class loader.
  856.      *
  857.      * @return A new {@code ModelContext} instance.
  858.      *
  859.      * @throws ModelException if creating a new {@code ModelContext} instance fails.
  860.      *
  861.      * @see #getModelContextClassName()
  862.      *
  863.      * @deprecated As of JOMC 1.2, replaced by method {@link ModelContextFactory#newModelContext(java.lang.ClassLoader)}.
  864.      * This method will be removed in version 2.0.
  865.      */
  866.     public static ModelContext createModelContext( final ClassLoader classLoader ) throws ModelException
  867.     {
  868.         if ( getModelContextClassName().equals( DefaultModelContext.class.getName() ) )
  869.         {
  870.             return new DefaultModelContext( classLoader );
  871.         }

  872.         try
  873.         {
  874.             final Class<?> clazz = Class.forName( getModelContextClassName(), false, classLoader );

  875.             if ( !ModelContext.class.isAssignableFrom( clazz ) )
  876.             {
  877.                 throw new ModelException( getMessage( "illegalContextImplementation", getModelContextClassName(),
  878.                                                       ModelContext.class.getName() ) );

  879.             }

  880.             final Constructor<? extends ModelContext> ctor =
  881.                 clazz.asSubclass( ModelContext.class ).getDeclaredConstructor( ClassLoader.class );

  882.             return ctor.newInstance( classLoader );
  883.         }
  884.         catch ( final ClassNotFoundException e )
  885.         {
  886.             throw new ModelException( getMessage( "contextClassNotFound", getModelContextClassName() ), e );
  887.         }
  888.         catch ( final NoSuchMethodException e )
  889.         {
  890.             throw new ModelException( getMessage( "contextConstructorNotFound", getModelContextClassName() ), e );
  891.         }
  892.         catch ( final InstantiationException e )
  893.         {
  894.             final String message = getMessage( e );
  895.             throw new ModelException( getMessage( "contextInstantiationException", getModelContextClassName(),
  896.                                                   message != null ? " " + message : "" ), e );

  897.         }
  898.         catch ( final IllegalAccessException e )
  899.         {
  900.             final String message = getMessage( e );
  901.             throw new ModelException( getMessage( "contextConstructorAccessDenied", getModelContextClassName(),
  902.                                                   message != null ? " " + message : "" ), e );

  903.         }
  904.         catch ( final InvocationTargetException e )
  905.         {
  906.             String message = getMessage( e );
  907.             if ( message == null && e.getTargetException() != null )
  908.             {
  909.                 message = getMessage( e.getTargetException() );
  910.             }

  911.             throw new ModelException( getMessage( "contextConstructorException", getModelContextClassName(),
  912.                                                   message != null ? " " + message : "" ), e );

  913.         }
  914.     }

  915.     /**
  916.      * Processes a {@code Model}.
  917.      *
  918.      * @param model The {@code Model} to process.
  919.      *
  920.      * @return The processed {@code Model}.
  921.      *
  922.      * @throws NullPointerException if {@code model} is {@code null}.
  923.      * @throws ModelException if processing {@code model} fails.
  924.      *
  925.      * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelProcessor.class.getName(), ModelProcessor.class )
  926.      */
  927.     public abstract Model processModel( Model model ) throws ModelException;

  928.     /**
  929.      * Validates a given {@code Model}.
  930.      *
  931.      * @param model The {@code Model} to validate.
  932.      *
  933.      * @return Validation report.
  934.      *
  935.      * @throws NullPointerException if {@code model} is {@code null}.
  936.      * @throws ModelException if validating {@code model} fails.
  937.      *
  938.      * @see #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class) createServiceObjects( model, ModelValidator.class.getName(), ModelValidator.class )
  939.      * @see ModelValidationReport#isModelValid()
  940.      */
  941.     public abstract ModelValidationReport validateModel( Model model ) throws ModelException;

  942.     /**
  943.      * Validates a given model.
  944.      *
  945.      * @param model The identifier of the {@code Model} to use for validating {@code source}.
  946.      * @param source A source providing the model to validate.
  947.      *
  948.      * @return Validation report.
  949.      *
  950.      * @throws NullPointerException if {@code model} or {@code source} is {@code null}.
  951.      * @throws ModelException if validating the model fails.
  952.      *
  953.      * @see #createSchema(java.lang.String)
  954.      * @see ModelValidationReport#isModelValid()
  955.      * @see ModletObject#MODEL_PUBLIC_ID
  956.      */
  957.     public abstract ModelValidationReport validateModel( String model, Source source ) throws ModelException;

  958.     /**
  959.      * Creates a new SAX entity resolver instance of a given model.
  960.      *
  961.      * @param model The identifier of the model to create a new SAX entity resolver of.
  962.      *
  963.      * @return A new SAX entity resolver instance of the model identified by {@code model}.
  964.      *
  965.      * @throws NullPointerException if {@code model} is {@code null}.
  966.      * @throws ModelException if creating a new SAX entity resolver instance fails.
  967.      *
  968.      * @see ModletObject#MODEL_PUBLIC_ID
  969.      */
  970.     public abstract EntityResolver createEntityResolver( String model ) throws ModelException;

  971.     /**
  972.      * Creates a new SAX entity resolver instance for a given public identifier URI.
  973.      *
  974.      * @param publicId The public identifier URI to create a new SAX entity resolver for.
  975.      *
  976.      * @return A new SAX entity resolver instance for the public identifier URI {@code publicId}.
  977.      *
  978.      * @throws NullPointerException if {@code publicId} is {@code null}.
  979.      * @throws ModelException if creating a new SAX entity resolver instance fails.
  980.      *
  981.      * @see ModletObject#PUBLIC_ID
  982.      * @since 1.2
  983.      * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0.
  984.      */
  985.     @Deprecated
  986.     public abstract EntityResolver createEntityResolver( URI publicId ) throws ModelException;

  987.     /**
  988.      * Creates a new L/S resource resolver instance of a given model.
  989.      *
  990.      * @param model The identifier of the model to create a new L/S resource resolver of.
  991.      *
  992.      * @return A new L/S resource resolver instance of the model identified by {@code model}.
  993.      *
  994.      * @throws NullPointerException if {@code model} is {@code null}.
  995.      * @throws ModelException if creating a new L/S resource resolver instance fails.
  996.      *
  997.      * @see ModletObject#MODEL_PUBLIC_ID
  998.      */
  999.     public abstract LSResourceResolver createResourceResolver( String model ) throws ModelException;

  1000.     /**
  1001.      * Creates a new L/S resource resolver instance for a given public identifier URI.
  1002.      *
  1003.      * @param publicId The public identifier URI to create a new L/S resource resolver for.
  1004.      *
  1005.      * @return A new L/S resource resolver instance for the public identifier URI {@code publicId}.
  1006.      *
  1007.      * @throws NullPointerException if {@code publicId} is {@code null}.
  1008.      * @throws ModelException if creating a new L/S resource resolver instance fails.
  1009.      *
  1010.      * @see ModletObject#PUBLIC_ID
  1011.      * @since 1.2
  1012.      * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0.
  1013.      */
  1014.     @Deprecated
  1015.     public abstract LSResourceResolver createResourceResolver( URI publicId ) throws ModelException;

  1016.     /**
  1017.      * Creates a new JAXP schema instance of a given model.
  1018.      *
  1019.      * @param model The identifier of the model to create a new JAXP schema instance of.
  1020.      *
  1021.      * @return A new JAXP schema instance of the model identified by {@code model}.
  1022.      *
  1023.      * @throws NullPointerException if {@code model} is {@code null}.
  1024.      * @throws ModelException if creating a new JAXP schema instance fails.
  1025.      *
  1026.      * @see ModletObject#MODEL_PUBLIC_ID
  1027.      */
  1028.     public abstract javax.xml.validation.Schema createSchema( String model ) throws ModelException;

  1029.     /**
  1030.      * Creates a new JAXP schema instance for a given public identifier URI.
  1031.      *
  1032.      * @param publicId The public identifier URI to create a new JAXP schema instance for.
  1033.      *
  1034.      * @return A new JAXP schema instance for the public identifier URI {@code publicId}.
  1035.      *
  1036.      * @throws NullPointerException if {@code publicId} is {@code null}.
  1037.      * @throws ModelException if creating a new JAXP schema instance fails.
  1038.      *
  1039.      * @see ModletObject#PUBLIC_ID
  1040.      * @since 1.2
  1041.      * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0.
  1042.      */
  1043.     @Deprecated
  1044.     public abstract javax.xml.validation.Schema createSchema( URI publicId ) throws ModelException;

  1045.     /**
  1046.      * Creates a new JAXB context instance of a given model.
  1047.      *
  1048.      * @param model The identifier of the model to create a new JAXB context instance of.
  1049.      *
  1050.      * @return A new JAXB context instance of the model identified by {@code model}.
  1051.      *
  1052.      * @throws NullPointerException if {@code model} is {@code null}.
  1053.      * @throws ModelException if creating a new JAXB context instance fails.
  1054.      *
  1055.      * @see ModletObject#MODEL_PUBLIC_ID
  1056.      */
  1057.     public abstract JAXBContext createContext( String model ) throws ModelException;

  1058.     /**
  1059.      * Creates a new JAXB context instance for a given public identifier URI.
  1060.      *
  1061.      * @param publicId The public identifier URI to create a new JAXB context instance for.
  1062.      *
  1063.      * @return A new JAXB context instance for the public identifier URI {@code publicId}.
  1064.      *
  1065.      * @throws NullPointerException if {@code publicId} is {@code null}.
  1066.      * @throws ModelException if creating a new JAXB context instance fails.
  1067.      *
  1068.      * @see ModletObject#PUBLIC_ID
  1069.      * @since 1.2
  1070.      * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0.
  1071.      */
  1072.     @Deprecated
  1073.     public abstract JAXBContext createContext( URI publicId ) throws ModelException;

  1074.     /**
  1075.      * Creates a new JAXB marshaller instance of a given model.
  1076.      *
  1077.      * @param model The identifier of the model to create a new JAXB marshaller instance of.
  1078.      *
  1079.      * @return A new JAXB marshaller instance of the model identified by {@code model}.
  1080.      *
  1081.      * @throws NullPointerException if {@code model} is {@code null}.
  1082.      * @throws ModelException if creating a new JAXB marshaller instance fails.
  1083.      *
  1084.      * @see ModletObject#MODEL_PUBLIC_ID
  1085.      */
  1086.     public abstract Marshaller createMarshaller( String model ) throws ModelException;

  1087.     /**
  1088.      * Creates a new JAXB marshaller instance for a given public identifier URI.
  1089.      *
  1090.      * @param publicId The public identifier URI to create a new JAXB marshaller instance for.
  1091.      *
  1092.      * @return A new JAXB marshaller instance for the public identifier URI {@code publicId}.
  1093.      *
  1094.      * @throws NullPointerException if {@code publicId} is {@code null}.
  1095.      * @throws ModelException if creating a new JAXB marshaller instance fails.
  1096.      *
  1097.      * @see ModletObject#PUBLIC_ID
  1098.      * @since 1.2
  1099.      * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0.
  1100.      */
  1101.     @Deprecated
  1102.     public abstract Marshaller createMarshaller( URI publicId ) throws ModelException;

  1103.     /**
  1104.      * Creates a new JAXB unmarshaller instance of a given model.
  1105.      *
  1106.      * @param model The identifier of the model to create a new JAXB unmarshaller instance of.
  1107.      *
  1108.      * @return A new JAXB unmarshaller 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 unmarshaller instance fails.
  1112.      *
  1113.      * @see ModletObject#MODEL_PUBLIC_ID
  1114.      */
  1115.     public abstract Unmarshaller createUnmarshaller( String model ) throws ModelException;

  1116.     /**
  1117.      * Creates a new JAXB unmarshaller instance for a given given public identifier URI.
  1118.      *
  1119.      * @param publicId The public identifier URI to create a new JAXB unmarshaller instance for.
  1120.      *
  1121.      * @return A new JAXB unmarshaller instance for the public identifier URI {@code publicId}.
  1122.      *
  1123.      * @throws NullPointerException if {@code publicId} is {@code null}.
  1124.      * @throws ModelException if creating a new JAXB unmarshaller instance fails.
  1125.      *
  1126.      * @see ModletObject#PUBLIC_ID
  1127.      * @since 1.2
  1128.      * @deprecated As of JOMC 1.8, removed without replacement. This method will be removed in JOMC 2.0.
  1129.      */
  1130.     @Deprecated
  1131.     public abstract Unmarshaller createUnmarshaller( URI publicId ) throws ModelException;

  1132.     /**
  1133.      * Creates service objects of a model.
  1134.      *
  1135.      * @param <T> The type of the service.
  1136.      * @param model The identifier of the {@code Model} to create service objects of.
  1137.      * @param service The identifier of the service to create objects of.
  1138.      * @param type The class of the type of the service.
  1139.      *
  1140.      * @return An ordered, unmodifiable collection of new service objects identified by {@code service} of the model
  1141.      * identified by {@code model}.
  1142.      *
  1143.      * @throws NullPointerException if {@code model}, {@code service} or {@code type} is {@code null}.
  1144.      * @throws ModelException if creating service objects fails.
  1145.      *
  1146.      * @see ModelProvider
  1147.      * @see ModelProcessor
  1148.      * @see ModelValidator
  1149.      *
  1150.      * @since 1.9
  1151.      */
  1152.     public abstract <T> Collection<? extends T> createServiceObjects( final String model, final String service,
  1153.                                                                       final Class<T> type )
  1154.         throws ModelException;

  1155.     /**
  1156.      * Creates a new service object.
  1157.      *
  1158.      * @param <T> The type of the service.
  1159.      * @param service The service to create a new object of.
  1160.      * @param type The class of the type of the service.
  1161.      *
  1162.      * @return An new service object for {@code service}.
  1163.      *
  1164.      * @throws NullPointerException if {@code service} or {@code type} is {@code null}.
  1165.      * @throws ModelException if creating the service object fails.
  1166.      *
  1167.      * @see ModletProvider
  1168.      * @see ModletProcessor
  1169.      * @see ModletValidator
  1170.      * @see ServiceFactory
  1171.      *
  1172.      * @since 1.2
  1173.      * @deprecated As of JOMC 1.9, please use method {@link #createServiceObjects(java.lang.String, java.lang.String, java.lang.Class)}.
  1174.      * This method will be removed in JOMC 2.0.
  1175.      */
  1176.     @Deprecated
  1177.     public abstract <T> T createServiceObject( final Service service, final Class<T> type ) throws ModelException;

  1178.     private static String getMessage( final String key, final Object... args )
  1179.     {
  1180.         return MessageFormat.format( ResourceBundle.getBundle(
  1181.             ModelContext.class.getName().replace( '.', '/' ), Locale.getDefault() ).getString( key ), args );

  1182.     }

  1183.     private static String getMessage( final Throwable t )
  1184.     {
  1185.         return t != null
  1186.                    ? t.getMessage() != null && t.getMessage().trim().length() > 0
  1187.                          ? t.getMessage()
  1188.                          : getMessage( t.getCause() )
  1189.                    : null;

  1190.     }

  1191. }