EMMA Coverage Report (generated Tue Nov 18 06:49:09 CET 2014)
[all classes][org.jomc.modlet]

COVERAGE SUMMARY FOR SOURCE FILE [DefaultModelContext.java]

nameclass, %method, %block, %line, %
DefaultModelContext.java100% (10/10)95%  (86/91)83%  (3943/4736)82%  (666.7/811)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DefaultModelContext$5100% (1/1)25%  (1/4)18%  (6/34)11%  (1/9)
error (SAXParseException): void 0%   (0/1)0%   (0/2)0%   (0/1)
fatalError (SAXParseException): void 0%   (0/1)0%   (0/2)0%   (0/1)
warning (SAXParseException): void 0%   (0/1)0%   (0/24)0%   (0/6)
DefaultModelContext$5 (DefaultModelContext): void 100% (1/1)100% (6/6)100% (1/1)
     
class DefaultModelContext$4100% (1/1)100% (2/2)31%  (62/202)30%  (11.5/38)
resolveResource (String, String, String, String, String): LSInput 100% (1/1)27%  (53/193)28%  (10.5/37)
DefaultModelContext$4 (DefaultModelContext, EntityResolver): void 100% (1/1)100% (9/9)100% (1/1)
     
class ModelErrorHandler100% (1/1)71%  (5/7)44%  (71/161)50%  (15.4/31)
fatalError (SAXParseException): void 0%   (0/1)0%   (0/39)0%   (0/7)
warning (SAXParseException): void 0%   (0/1)0%   (0/39)0%   (0/7)
getMessage (Throwable): String 100% (1/1)74%  (14/19)73%  (0.7/1)
error (SAXParseException): void 100% (1/1)82%  (32/39)80%  (5.6/7)
ModelErrorHandler (ModelContext): void 100% (1/1)100% (5/5)100% (2/2)
ModelErrorHandler (ModelContext, ModelValidationReport): void 100% (1/1)100% (9/9)100% (4/4)
getReport (): ModelValidationReport 100% (1/1)100% (11/11)100% (3/3)
     
class DefaultModelContext$3100% (1/1)100% (2/2)65%  (220/336)69%  (38.6/56)
resolveEntity (String, String): InputSource 100% (1/1)65%  (211/327)68%  (37.6/55)
DefaultModelContext$3 (DefaultModelContext, Schemas): void 100% (1/1)100% (9/9)100% (1/1)
     
class DefaultModelContext$2100% (1/1)100% (2/2)81%  (34/42)83%  (10/12)
compare (Object, Object): int 100% (1/1)78%  (28/36)82%  (9/11)
DefaultModelContext$2 (DefaultModelContext): void 100% (1/1)100% (6/6)100% (1/1)
     
class DefaultModelContext100% (1/1)100% (47/47)88%  (3131/3542)88%  (533.2/608)
validateModel (String, Source): ModelValidationReport 100% (1/1)60%  (61/102)58%  (14/24)
createResourceResolver (EntityResolver): LSResourceResolver 100% (1/1)62%  (8/13)67%  (2/3)
getMessage (Throwable): String 100% (1/1)74%  (14/19)73%  (0.7/1)
createContext (Schemas, String, URI): JAXBContext 100% (1/1)75%  (108/144)75%  (18/24)
createSchema (Schemas, EntityResolver, LSResourceResolver, String, URI): Schema 100% (1/1)76%  (154/203)74%  (26/35)
loadModletServices (Class): Collection 100% (1/1)81%  (318/394)79%  (53.6/68)
createServiceObject (Class, String, URL): Object 100% (1/1)85%  (154/182)87%  (27/31)
getSchemaResources (): Set 100% (1/1)85%  (184/217)81%  (32.3/40)
createUnmarshaller (Schemas, Services, String, URI): Unmarshaller 100% (1/1)85%  (204/240)84%  (32/38)
createMarshaller (Schemas, Services, String, URI): Marshaller 100% (1/1)88%  (256/292)86%  (38/44)
processModlets (Modlets): Modlets 100% (1/1)91%  (48/53)92%  (11/12)
setProperty (Object, String, String): void 100% (1/1)91%  (523/576)91%  (97.8/107)
findModlets (Modlets): Modlets 100% (1/1)96%  (215/223)99%  (23.8/24)
<static initializer> 100% (1/1)100% (25/25)100% (2/2)
DefaultModelContext (): void 100% (1/1)100% (9/9)100% (3/3)
DefaultModelContext (ClassLoader): void 100% (1/1)100% (10/10)100% (3/3)
access$000 (String, Object []): String 100% (1/1)100% (4/4)100% (1/1)
access$100 (DefaultModelContext): Set 100% (1/1)100% (3/3)100% (1/1)
access$200 (Throwable): String 100% (1/1)100% (3/3)100% (1/1)
createContext (String): JAXBContext 100% (1/1)100% (16/16)100% (3/3)
createContext (URI): JAXBContext 100% (1/1)100% (16/16)100% (3/3)
createEntityResolver (Schemas): EntityResolver 100% (1/1)100% (6/6)100% (1/1)
createEntityResolver (String): EntityResolver 100% (1/1)100% (14/14)100% (3/3)
createEntityResolver (URI): EntityResolver 100% (1/1)100% (14/14)100% (3/3)
createMarshaller (String): Marshaller 100% (1/1)100% (20/20)100% (3/3)
createMarshaller (URI): Marshaller 100% (1/1)100% (17/17)100% (3/3)
createResourceResolver (String): LSResourceResolver 100% (1/1)100% (13/13)100% (3/3)
createResourceResolver (URI): LSResourceResolver 100% (1/1)100% (13/13)100% (3/3)
createSchema (String): Schema 100% (1/1)100% (22/22)100% (3/3)
createSchema (URI): Schema 100% (1/1)100% (22/22)100% (3/3)
createServiceObject (Service, Class): Object 100% (1/1)100% (139/139)100% (18/18)
createUnmarshaller (String): Unmarshaller 100% (1/1)100% (20/20)100% (3/3)
createUnmarshaller (URI): Unmarshaller 100% (1/1)100% (17/17)100% (3/3)
findModel (Model): Model 100% (1/1)100% (96/96)100% (17/17)
findModel (String): Model 100% (1/1)100% (18/18)100% (5/5)
findModlets (): Modlets 100% (1/1)100% (6/6)100% (1/1)
getDefaultPlatformProviderLocation (): String 100% (1/1)100% (8/8)100% (3/3)
getDefaultProviderLocation (): String 100% (1/1)100% (8/8)100% (3/3)
getMessage (String, Object []): String 100% (1/1)100% (11/11)100% (1/1)
getPlatformProviderLocation (): String 100% (1/1)100% (62/62)100% (11/11)
getProviderLocation (): String 100% (1/1)100% (62/62)100% (11/11)
processModel (Model): Model 100% (1/1)100% (95/95)100% (17/17)
setDefaultPlatformProviderLocation (String): void 100% (1/1)100% (3/3)100% (2/2)
setDefaultProviderLocation (String): void 100% (1/1)100% (3/3)100% (2/2)
setPlatformProviderLocation (String): void 100% (1/1)100% (4/4)100% (2/2)
setProviderLocation (String): void 100% (1/1)100% (4/4)100% (2/2)
validateModel (Model): ModelValidationReport 100% (1/1)100% (101/101)100% (17/17)
     
class DefaultModelContext$1100% (1/1)100% (2/2)100% (10/10)100% (2/2)
DefaultModelContext$1 (DefaultModelContext): void 100% (1/1)100% (6/6)100% (1/1)
compare (String, String): int 100% (1/1)100% (4/4)100% (1/1)
     
class DefaultModelContext$4$1100% (1/1)100% (17/17)100% (303/303)100% (33/33)
DefaultModelContext$4$1 (DefaultModelContext$4, InputSource, String): void 100% (1/1)100% (12/12)100% (1/1)
getBaseURI (): String 100% (1/1)100% (3/3)100% (1/1)
getByteStream (): InputStream 100% (1/1)100% (4/4)100% (1/1)
getCertifiedText (): boolean 100% (1/1)100% (2/2)100% (1/1)
getCharacterStream (): Reader 100% (1/1)100% (4/4)100% (1/1)
getEncoding (): String 100% (1/1)100% (4/4)100% (1/1)
getPublicId (): String 100% (1/1)100% (4/4)100% (1/1)
getStringData (): String 100% (1/1)100% (2/2)100% (1/1)
getSystemId (): String 100% (1/1)100% (4/4)100% (1/1)
setBaseURI (String): void 100% (1/1)100% (33/33)100% (3/3)
setByteStream (InputStream): void 100% (1/1)100% (33/33)100% (3/3)
setCertifiedText (boolean): void 100% (1/1)100% (33/33)100% (3/3)
setCharacterStream (Reader): void 100% (1/1)100% (33/33)100% (3/3)
setEncoding (String): void 100% (1/1)100% (33/33)100% (3/3)
setPublicId (String): void 100% (1/1)100% (33/33)100% (3/3)
setStringData (String): void 100% (1/1)100% (33/33)100% (3/3)
setSystemId (String): void 100% (1/1)100% (33/33)100% (3/3)
     
class MarshallerListenerList100% (1/1)100% (4/4)100% (52/52)100% (11/11)
MarshallerListenerList (): void 100% (1/1)100% (3/3)100% (2/2)
afterMarshal (Object): void 100% (1/1)100% (19/19)100% (3/3)
beforeMarshal (Object): void 100% (1/1)100% (19/19)100% (3/3)
getListeners (): List 100% (1/1)100% (11/11)100% (3/3)
     
class UnmarshallerListenerList100% (1/1)100% (4/4)100% (54/54)100% (11/11)
UnmarshallerListenerList (): void 100% (1/1)100% (3/3)100% (2/2)
afterUnmarshal (Object, Object): void 100% (1/1)100% (20/20)100% (3/3)
beforeUnmarshal (Object, Object): void 100% (1/1)100% (20/20)100% (3/3)
getListeners (): List 100% (1/1)100% (11/11)100% (3/3)

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

[all classes][org.jomc.modlet]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov