EMMA Coverage Report (generated Wed Mar 26 15:19:37 CET 2014)
[all classes][org.jomc.modlet]

COVERAGE SUMMARY FOR SOURCE FILE [DefaultModelContext.java]

nameclass, %method, %block, %line, %
DefaultModelContext.java100% (10/10)96%  (87/91)82%  (3902/4776)81%  (666.3/819)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DefaultModelContext$5100% (1/1)50%  (2/4)24%  (8/34)22%  (2/9)
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)
error (SAXParseException): void 100% (1/1)100% (2/2)100% (1/1)
     
class DefaultModelContext$4100% (1/1)100% (2/2)30%  (61/202)30%  (11.4/38)
resolveResource (String, String, String, String, String): LSInput 100% (1/1)27%  (52/193)28%  (10.4/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)61%  (229/376)64%  (41.1/64)
resolveEntity (String, String): InputSource 100% (1/1)60%  (220/367)64%  (40.1/63)
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)87%  (3080/3542)87%  (529.4/608)
getSchemaResources (): Set 100% (1/1)54%  (117/217)62%  (24.8/40)
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)
loadModletServices (Class): Collection 100% (1/1)81%  (318/394)79%  (53.6/68)
createSchema (Schemas, EntityResolver, LSResourceResolver, String, URI): Schema 100% (1/1)82%  (166/203)85%  (29.7/35)
createServiceObject (Class, String, URL): Object 100% (1/1)85%  (154/182)87%  (27/31)
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)98%  (219/223)100% (23.9/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 (Throwable): String 100% (1/1)100% (3/3)100% (1/1)
access$100 (String, Object []): String 100% (1/1)100% (4/4)100% (1/1)
access$200 (DefaultModelContext): Set 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 4939 2014-03-25 03:47:18Z 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 4939 2014-03-25 03:47:18Z 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    public EntityResolver createEntityResolver( final URI publicId ) throws ModelException
628    {
629        if ( publicId == null )
630        {
631            throw new NullPointerException( "publicId" );
632        }
633 
634        return this.createEntityResolver( this.getModlets().getSchemas( publicId ) );
635    }
636 
637    @Override
638    public LSResourceResolver createResourceResolver( final String model ) throws ModelException
639    {
640        if ( model == null )
641        {
642            throw new NullPointerException( "model" );
643        }
644 
645        return this.createResourceResolver( this.createEntityResolver( model ) );
646    }
647 
648    @Override
649    public LSResourceResolver createResourceResolver( final URI publicId ) throws ModelException
650    {
651        if ( publicId == null )
652        {
653            throw new NullPointerException( "publicId" );
654        }
655 
656        return this.createResourceResolver( this.createEntityResolver( publicId ) );
657    }
658 
659    @Override
660    public javax.xml.validation.Schema createSchema( final String model ) throws ModelException
661    {
662        if ( model == null )
663        {
664            throw new NullPointerException( "model" );
665        }
666 
667        return this.createSchema( this.getModlets().getSchemas( model ), this.createEntityResolver( model ),
668                                  this.createResourceResolver( model ), model, null );
669 
670    }
671 
672    @Override
673    public javax.xml.validation.Schema createSchema( final URI publicId ) throws ModelException
674    {
675        if ( publicId == null )
676        {
677            throw new NullPointerException( "publicId" );
678        }
679 
680        return this.createSchema( this.getModlets().getSchemas( publicId ), this.createEntityResolver( publicId ),
681                                  this.createResourceResolver( publicId ), null, publicId );
682 
683    }
684 
685    @Override
686    public JAXBContext createContext( final String model ) throws ModelException
687    {
688        if ( model == null )
689        {
690            throw new NullPointerException( "model" );
691        }
692 
693        return this.createContext( this.getModlets().getSchemas( model ), model, null );
694    }
695 
696    @Override
697    public JAXBContext createContext( final URI publicId ) throws ModelException
698    {
699        if ( publicId == null )
700        {
701            throw new NullPointerException( "publicId" );
702        }
703 
704        return this.createContext( this.getModlets().getSchemas( publicId ), null, publicId );
705    }
706 
707    @Override
708    public Marshaller createMarshaller( final String model ) throws ModelException
709    {
710        if ( model == null )
711        {
712            throw new NullPointerException( "model" );
713        }
714 
715        return this.createMarshaller( this.getModlets().getSchemas( model ), this.getModlets().getServices( model ),
716                                      model, null );
717 
718    }
719 
720    @Override
721    public Marshaller createMarshaller( final URI publicId ) throws ModelException
722    {
723        if ( publicId == null )
724        {
725            throw new NullPointerException( "publicId" );
726        }
727 
728        return this.createMarshaller( this.getModlets().getSchemas( publicId ), null, null, publicId );
729    }
730 
731    @Override
732    public Unmarshaller createUnmarshaller( final String model ) throws ModelException
733    {
734        if ( model == null )
735        {
736            throw new NullPointerException( "model" );
737        }
738 
739        return this.createUnmarshaller( this.getModlets().getSchemas( model ), this.getModlets().getServices( model ),
740                                        model, null );
741 
742    }
743 
744    @Override
745    public Unmarshaller createUnmarshaller( final URI publicId ) throws ModelException
746    {
747        if ( publicId == null )
748        {
749            throw new NullPointerException( "publicId" );
750        }
751 
752        return this.createUnmarshaller( this.getModlets().getSchemas( publicId ), null, null, publicId );
753    }
754 
755    /**
756     * {@inheritDoc}
757     * <p>This method loads all {@code ModelProcessor} service classes of {@code model} to process the given
758     * {@code Model}.</p>
759     *
760     * @see #createServiceObject(org.jomc.modlet.Service, java.lang.Class)
761     * @see ModelProcessor#processModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
762     */
763    @Override
764    public Model processModel( final Model model ) throws ModelException
765    {
766        if ( model == null )
767        {
768            throw new NullPointerException( "model" );
769        }
770 
771        Model processed = model;
772        final long t0 = System.currentTimeMillis();
773        final Services services = this.getModlets().getServices( model.getIdentifier() );
774 
775        if ( services != null )
776        {
777            for ( Service service : services.getServices( ModelProcessor.class ) )
778            {
779                final ModelProcessor modelProcessor = this.createServiceObject( service, ModelProcessor.class );
780 
781                if ( this.isLoggable( Level.FINER ) )
782                {
783                    this.log( Level.FINER, getMessage( "processingModel", model.getIdentifier(),
784                                                       modelProcessor.toString() ), null );
785 
786                }
787 
788                final Model current = modelProcessor.processModel( this, processed );
789 
790                if ( current != null )
791                {
792                    processed = current;
793                }
794            }
795        }
796 
797        if ( this.isLoggable( Level.FINE ) )
798        {
799            this.log( Level.FINE, getMessage( "processModelReport", model.getIdentifier(),
800                                              System.currentTimeMillis() - t0 ), null );
801 
802        }
803 
804        return processed;
805    }
806 
807    /**
808     * {@inheritDoc}
809     * <p>This method loads all {@code ModelValidator} service classes of {@code model} to validate the given
810     * {@code Model}.</p>
811     *
812     * @see #createServiceObject(org.jomc.modlet.Service, java.lang.Class)
813     * @see ModelValidator#validateModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
814     */
815    @Override
816    public ModelValidationReport validateModel( final Model model ) throws ModelException
817    {
818        if ( model == null )
819        {
820            throw new NullPointerException( "model" );
821        }
822 
823        final long t0 = System.currentTimeMillis();
824        final Services services = this.getModlets().getServices( model.getIdentifier() );
825        final ModelValidationReport report = new ModelValidationReport();
826 
827        if ( services != null )
828        {
829            for ( Service service : services.getServices( ModelValidator.class ) )
830            {
831                final ModelValidator modelValidator = this.createServiceObject( service, ModelValidator.class );
832 
833                if ( this.isLoggable( Level.FINER ) )
834                {
835                    this.log( Level.FINER, getMessage( "validatingModel", model.getIdentifier(),
836                                                       modelValidator.toString() ), null );
837 
838                }
839 
840                final ModelValidationReport current = modelValidator.validateModel( this, model );
841 
842                if ( current != null )
843                {
844                    report.getDetails().addAll( current.getDetails() );
845                }
846            }
847        }
848 
849        if ( this.isLoggable( Level.FINE ) )
850        {
851            this.log( Level.FINE, getMessage( "validateModelReport", model.getIdentifier(),
852                                              System.currentTimeMillis() - t0 ), null );
853 
854        }
855 
856        return report;
857    }
858 
859    /**
860     * {@inheritDoc}
861     *
862     * @see #createSchema(java.lang.String)
863     */
864    @Override
865    public ModelValidationReport validateModel( final String model, final Source source ) throws ModelException
866    {
867        if ( model == null )
868        {
869            throw new NullPointerException( "model" );
870        }
871        if ( source == null )
872        {
873            throw new NullPointerException( "source" );
874        }
875 
876        final long t0 = System.currentTimeMillis();
877        final javax.xml.validation.Schema schema = this.createSchema( model );
878        final Validator validator = schema.newValidator();
879        final ModelErrorHandler modelErrorHandler = new ModelErrorHandler( this );
880        validator.setErrorHandler( modelErrorHandler );
881 
882        try
883        {
884            validator.validate( source );
885        }
886        catch ( final SAXException e )
887        {
888            String message = getMessage( e );
889            if ( message == null && e.getException() != null )
890            {
891                message = getMessage( e.getException() );
892            }
893 
894            if ( this.isLoggable( Level.FINE ) )
895            {
896                this.log( Level.FINE, message, e );
897            }
898 
899            if ( modelErrorHandler.getReport().isModelValid() )
900            {
901                throw new ModelException( message, e );
902            }
903        }
904        catch ( final IOException e )
905        {
906            throw new ModelException( getMessage( e ), e );
907        }
908 
909        if ( this.isLoggable( Level.FINE ) )
910        {
911            this.log( Level.FINE, getMessage( "validateModelReport", model, System.currentTimeMillis() - t0 ), null );
912        }
913 
914        return modelErrorHandler.getReport();
915    }
916 
917    private <T> Collection<T> loadModletServices( final Class<T> serviceClass ) throws ModelException
918    {
919        try
920        {
921            final String serviceNamePrefix = serviceClass.getName() + ".";
922            final Map<String, T> sortedPlatformServices = new TreeMap<String, T>( new Comparator<String>()
923            {
924 
925                public int compare( final String key1, final String key2 )
926                {
927                    return key1.compareTo( key2 );
928                }
929 
930            } );
931 
932            final File platformServices = new File( this.getPlatformProviderLocation() );
933 
934            if ( platformServices.exists() )
935            {
936                if ( this.isLoggable( Level.FINEST ) )
937                {
938                    this.log( Level.FINEST, getMessage( "processing", platformServices.getAbsolutePath() ), null );
939                }
940 
941                InputStream in = null;
942                boolean suppressExceptionOnClose = true;
943                final java.util.Properties p = new java.util.Properties();
944 
945                try
946                {
947                    in = new FileInputStream( platformServices );
948                    p.load( in );
949                    suppressExceptionOnClose = false;
950                }
951                finally
952                {
953                    try
954                    {
955                        if ( in != null )
956                        {
957                            in.close();
958                        }
959                    }
960                    catch ( final IOException e )
961                    {
962                        if ( suppressExceptionOnClose )
963                        {
964                            this.log( Level.SEVERE, getMessage( e ), e );
965                        }
966                        else
967                        {
968                            throw e;
969                        }
970                    }
971                }
972 
973                for ( final Map.Entry<Object, Object> e : p.entrySet() )
974                {
975                    if ( e.getKey().toString().startsWith( serviceNamePrefix ) )
976                    {
977                        final String configuration = e.getValue().toString();
978 
979                        if ( this.isLoggable( Level.FINEST ) )
980                        {
981                            this.log( Level.FINEST, getMessage( "serviceInfo", platformServices.getAbsolutePath(),
982                                                                serviceClass.getName(), configuration ), null );
983 
984                        }
985 
986                        sortedPlatformServices.put( e.getKey().toString(),
987                                                    this.createServiceObject( serviceClass, configuration,
988                                                                              platformServices.toURI().toURL() ) );
989 
990                    }
991                }
992            }
993 
994            final Enumeration<URL> classpathServices =
995                this.findResources( this.getProviderLocation() + '/' + serviceClass.getName() );
996 
997            int count = 0;
998            final long t0 = System.currentTimeMillis();
999            final List<T> sortedClasspathServices = new ArrayList<T>();
1000 
1001            while ( classpathServices.hasMoreElements() )
1002            {
1003                count++;
1004                final URL url = classpathServices.nextElement();
1005 
1006                if ( this.isLoggable( Level.FINEST ) )
1007                {
1008                    this.log( Level.FINEST, getMessage( "processing", url.toExternalForm() ), null );
1009                }
1010 
1011                BufferedReader reader = null;
1012                boolean suppressExceptionOnClose = true;
1013 
1014                try
1015                {
1016                    reader = new BufferedReader( new InputStreamReader( url.openStream(), "UTF-8" ) );
1017 
1018                    String line;
1019                    while ( ( line = reader.readLine() ) != null )
1020                    {
1021                        if ( line.contains( "#" ) )
1022                        {
1023                            continue;
1024                        }
1025 
1026                        if ( this.isLoggable( Level.FINEST ) )
1027                        {
1028                            this.log( Level.FINEST, getMessage( "serviceInfo", url.toExternalForm(),
1029                                                                serviceClass.getName(), line ), null );
1030 
1031                        }
1032 
1033                        final T serviceObject = this.createServiceObject( serviceClass, line, url );
1034                        sortedClasspathServices.add( serviceObject );
1035                    }
1036 
1037                    Collections.sort( sortedClasspathServices,
1038                                      new Comparator<Object>()
1039                                      {
1040 
1041                                          public int compare( final Object o1, final Object o2 )
1042                                          {
1043                                              int ordinal1 = 0;
1044                                              int ordinal2 = 0;
1045 
1046                                              if ( o1 instanceof ModletProvider )
1047                                              {
1048                                                  ordinal1 = ( (ModletProvider) o1 ).getOrdinal();
1049                                              }
1050                                              if ( o1 instanceof ModletProcessor )
1051                                              {
1052                                                  ordinal1 = ( (ModletProcessor) o1 ).getOrdinal();
1053                                              }
1054                                              if ( o2 instanceof ModletProvider )
1055                                              {
1056                                                  ordinal2 = ( (ModletProvider) o2 ).getOrdinal();
1057                                              }
1058                                              if ( o2 instanceof ModletProcessor )
1059                                              {
1060                                                  ordinal2 = ( (ModletProcessor) o2 ).getOrdinal();
1061                                              }
1062 
1063                                              return ordinal1 - ordinal2;
1064                                          }
1065 
1066                                      } );
1067 
1068                    suppressExceptionOnClose = false;
1069                }
1070                finally
1071                {
1072                    try
1073                    {
1074                        if ( reader != null )
1075                        {
1076                            reader.close();
1077                        }
1078                    }
1079                    catch ( final IOException e )
1080                    {
1081                        if ( suppressExceptionOnClose )
1082                        {
1083                            this.log( Level.SEVERE, getMessage( e ), e );
1084                        }
1085                        else
1086                        {
1087                            throw new ModelException( getMessage( e ), e );
1088                        }
1089                    }
1090                }
1091            }
1092 
1093            if ( this.isLoggable( Level.FINE ) )
1094            {
1095                this.log( Level.FINE, getMessage( "contextReport", count,
1096                                                  this.getProviderLocation() + '/' + serviceClass.getName(),
1097                                                  System.currentTimeMillis() - t0 ), null );
1098 
1099            }
1100 
1101            final List<T> services =
1102                new ArrayList<T>( sortedPlatformServices.size() + sortedClasspathServices.size() );
1103 
1104            services.addAll( sortedPlatformServices.values() );
1105            services.addAll( sortedClasspathServices );
1106 
1107            return services;
1108        }
1109        catch ( final IOException e )
1110        {
1111            throw new ModelException( getMessage( e ), e );
1112        }
1113    }
1114 
1115    private <T> T createServiceObject( final Class<T> serviceClass, final String configuration, final URL location )
1116        throws ModelException
1117    {
1118        String className = configuration;
1119 
1120        try
1121        {
1122            final Map<String, String> properties = new HashMap<String, String>();
1123            final int i0 = configuration.indexOf( '[' );
1124            final int i1 = configuration.lastIndexOf( ']' );
1125 
1126            if ( i0 != -1 && i1 != -1 )
1127            {
1128                className = configuration.substring( 0, i0 );
1129                final StringTokenizer propertyTokens =
1130                    new StringTokenizer( configuration.substring( i0 + 1, i1 ), "," );
1131 
1132                while ( propertyTokens.hasMoreTokens() )
1133                {
1134                    final String property = propertyTokens.nextToken();
1135                    final int d0 = property.indexOf( '=' );
1136 
1137                    String propertyName = property;
1138                    String propertyValue = null;
1139 
1140                    if ( d0 != -1 )
1141                    {
1142                        propertyName = property.substring( 0, d0 );
1143                        propertyValue = property.substring( d0 + 1, property.length() );
1144                    }
1145 
1146                    properties.put( propertyName, propertyValue );
1147                }
1148            }
1149 
1150            final Class<?> service = this.findClass( className );
1151 
1152            if ( service == null )
1153            {
1154                throw new ModelException( getMessage( "implementationNotFound", serviceClass.getName(), className,
1155                                                      location.toExternalForm() ) );
1156 
1157            }
1158 
1159            if ( !serviceClass.isAssignableFrom( service ) )
1160            {
1161                throw new ModelException( getMessage( "illegalImplementation", serviceClass.getName(), className,
1162                                                      location.toExternalForm() ) );
1163 
1164            }
1165 
1166            final T o = service.asSubclass( serviceClass ).newInstance();
1167 
1168            for ( final Map.Entry<String, String> property : properties.entrySet() )
1169            {
1170                this.setProperty( o, property.getKey(), property.getValue() );
1171            }
1172 
1173            return o;
1174        }
1175        catch ( final InstantiationException e )
1176        {
1177            throw new ModelException( getMessage( "failedCreatingObject", className ), e );
1178        }
1179        catch ( final IllegalAccessException e )
1180        {
1181            throw new ModelException( getMessage( "failedCreatingObject", className ), e );
1182        }
1183    }
1184 
1185    private <T> void setProperty( final T object, final String propertyName, final String propertyValue )
1186        throws ModelException
1187    {
1188        if ( object == null )
1189        {
1190            throw new NullPointerException( "object" );
1191        }
1192        if ( propertyName == null )
1193        {
1194            throw new NullPointerException( "propertyName" );
1195        }
1196 
1197        try
1198        {
1199            final char[] chars = propertyName.toCharArray();
1200 
1201            if ( Character.isLowerCase( chars[0] ) )
1202            {
1203                chars[0] = Character.toUpperCase( chars[0] );
1204            }
1205 
1206            final String methodNameSuffix = String.valueOf( chars );
1207            Method getterMethod = null;
1208 
1209            try
1210            {
1211                getterMethod = object.getClass().getMethod( "get" + methodNameSuffix );
1212            }
1213            catch ( final NoSuchMethodException e )
1214            {
1215                if ( this.isLoggable( Level.FINEST ) )
1216                {
1217                    this.log( Level.FINEST, null, e );
1218                }
1219 
1220                getterMethod = null;
1221            }
1222 
1223            if ( getterMethod == null )
1224            {
1225                try
1226                {
1227                    getterMethod = object.getClass().getMethod( "is" + methodNameSuffix );
1228                }
1229                catch ( final NoSuchMethodException e )
1230                {
1231                    if ( this.isLoggable( Level.FINEST ) )
1232                    {
1233                        this.log( Level.FINEST, null, e );
1234                    }
1235 
1236                    getterMethod = null;
1237                }
1238            }
1239 
1240            if ( getterMethod == null )
1241            {
1242                throw new ModelException( getMessage( "getterMethodNotFound", object.getClass().getName(),
1243                                                      propertyName ) );
1244 
1245            }
1246 
1247            final Class<?> propertyType = getterMethod.getReturnType();
1248            Class<?> boxedPropertyType = propertyType;
1249            Class<?> unboxedPropertyType = propertyType;
1250 
1251            if ( Boolean.TYPE.equals( propertyType ) )
1252            {
1253                boxedPropertyType = Boolean.class;
1254            }
1255            else if ( Character.TYPE.equals( propertyType ) )
1256            {
1257                boxedPropertyType = Character.class;
1258            }
1259            else if ( Byte.TYPE.equals( propertyType ) )
1260            {
1261                boxedPropertyType = Byte.class;
1262            }
1263            else if ( Short.TYPE.equals( propertyType ) )
1264            {
1265                boxedPropertyType = Short.class;
1266            }
1267            else if ( Integer.TYPE.equals( propertyType ) )
1268            {
1269                boxedPropertyType = Integer.class;
1270            }
1271            else if ( Long.TYPE.equals( propertyType ) )
1272            {
1273                boxedPropertyType = Long.class;
1274            }
1275            else if ( Float.TYPE.equals( propertyType ) )
1276            {
1277                boxedPropertyType = Float.class;
1278            }
1279            else if ( Double.TYPE.equals( propertyType ) )
1280            {
1281                boxedPropertyType = Double.class;
1282            }
1283 
1284            if ( Boolean.class.equals( propertyType ) )
1285            {
1286                unboxedPropertyType = Boolean.TYPE;
1287            }
1288            else if ( Character.class.equals( propertyType ) )
1289            {
1290                unboxedPropertyType = Character.TYPE;
1291            }
1292            else if ( Byte.class.equals( propertyType ) )
1293            {
1294                unboxedPropertyType = Byte.TYPE;
1295            }
1296            else if ( Short.class.equals( propertyType ) )
1297            {
1298                unboxedPropertyType = Short.TYPE;
1299            }
1300            else if ( Integer.class.equals( propertyType ) )
1301            {
1302                unboxedPropertyType = Integer.TYPE;
1303            }
1304            else if ( Long.class.equals( propertyType ) )
1305            {
1306                unboxedPropertyType = Long.TYPE;
1307            }
1308            else if ( Float.class.equals( propertyType ) )
1309            {
1310                unboxedPropertyType = Float.TYPE;
1311            }
1312            else if ( Double.class.equals( propertyType ) )
1313            {
1314                unboxedPropertyType = Double.TYPE;
1315            }
1316 
1317            Method setterMethod = null;
1318 
1319            try
1320            {
1321                setterMethod = object.getClass().getMethod( "set" + methodNameSuffix, boxedPropertyType );
1322            }
1323            catch ( final NoSuchMethodException e )
1324            {
1325                if ( this.isLoggable( Level.FINEST ) )
1326                {
1327                    this.log( Level.FINEST, null, e );
1328                }
1329 
1330                setterMethod = null;
1331            }
1332 
1333            if ( setterMethod == null && !boxedPropertyType.equals( unboxedPropertyType ) )
1334            {
1335                try
1336                {
1337                    setterMethod = object.getClass().getMethod( "set" + methodNameSuffix, unboxedPropertyType );
1338                }
1339                catch ( final NoSuchMethodException e )
1340                {
1341                    if ( this.isLoggable( Level.FINEST ) )
1342                    {
1343                        this.log( Level.FINEST, null, e );
1344                    }
1345 
1346                    setterMethod = null;
1347                }
1348            }
1349 
1350            if ( setterMethod == null )
1351            {
1352                throw new ModelException( getMessage( "setterMethodNotFound", object.getClass().getName(),
1353                                                      propertyName ) );
1354 
1355            }
1356 
1357            if ( boxedPropertyType.equals( Character.class ) )
1358            {
1359                if ( propertyValue == null || propertyValue.length() != 1 )
1360                {
1361                    throw new ModelException( getMessage( "unsupportedCharacterValue", object.getClass().getName(),
1362                                                          propertyName ) );
1363 
1364                }
1365 
1366                setterMethod.invoke( object, Character.valueOf( propertyValue.charAt( 0 ) ) );
1367                return;
1368            }
1369 
1370            if ( propertyValue != null )
1371            {
1372                if ( boxedPropertyType.equals( String.class ) )
1373                {
1374                    setterMethod.invoke( object, propertyValue );
1375                    return;
1376                }
1377 
1378                try
1379                {
1380                    setterMethod.invoke(
1381                        object, boxedPropertyType.getConstructor( String.class ).newInstance( propertyValue ) );
1382 
1383                    return;
1384                }
1385                catch ( final NoSuchMethodException e )
1386                {
1387                    if ( this.isLoggable( Level.FINEST ) )
1388                    {
1389                        this.log( Level.FINEST, null, e );
1390                    }
1391                }
1392 
1393                try
1394                {
1395                    final Method valueOf = boxedPropertyType.getMethod( "valueOf", String.class );
1396 
1397                    if ( Modifier.isStatic( valueOf.getModifiers() )
1398                             && ( valueOf.getReturnType().equals( boxedPropertyType )
1399                                  || valueOf.getReturnType().equals( unboxedPropertyType ) ) )
1400                    {
1401                        setterMethod.invoke( object, valueOf.invoke( null, propertyValue ) );
1402                        return;
1403                    }
1404                }
1405                catch ( final NoSuchMethodException e )
1406                {
1407                    if ( this.isLoggable( Level.FINEST ) )
1408                    {
1409                        this.log( Level.FINEST, null, e );
1410                    }
1411                }
1412 
1413                throw new ModelException( getMessage( "unsupportedPropertyType", object.getClass().getName(),
1414                                                      propertyName, propertyType.getName() ) );
1415 
1416            }
1417            else
1418            {
1419                setterMethod.invoke( object, (Object) null );
1420            }
1421        }
1422        catch ( final IllegalAccessException e )
1423        {
1424            throw new ModelException( getMessage( "failedSettingProperty", propertyName, object.toString(),
1425                                                  object.getClass().getName() ), e );
1426 
1427        }
1428        catch ( final InvocationTargetException e )
1429        {
1430            throw new ModelException( getMessage( "failedSettingProperty", propertyName, object.toString(),
1431                                                  object.getClass().getName() ), e );
1432 
1433        }
1434        catch ( final InstantiationException e )
1435        {
1436            throw new ModelException( getMessage( "failedSettingProperty", propertyName, object.toString(),
1437                                                  object.getClass().getName() ), e );
1438 
1439        }
1440    }
1441 
1442    /**
1443     * Searches the context for {@code META-INF/MANIFEST.MF} resources and returns a set of URIs of entries whose names
1444     * end with a known schema extension.
1445     *
1446     * @return Set of URIs of any matching entries.
1447     *
1448     * @throws IOException if reading fails.
1449     * @throws URISyntaxException if parsing fails.
1450     * @throws ModelException if searching the context fails.
1451     */
1452    private Set<URI> getSchemaResources() throws IOException, URISyntaxException, ModelException
1453    {
1454        Set<URI> resources = this.cachedSchemaResources.get();
1455 
1456        if ( resources == null )
1457        {
1458            resources = new HashSet<URI>();
1459            final long t0 = System.currentTimeMillis();
1460            int count = 0;
1461 
1462            for ( final Enumeration<URL> e = this.findResources( "META-INF/MANIFEST.MF" );
1463                  e.hasMoreElements(); )
1464            {
1465                InputStream manifestStream = null;
1466                boolean suppressExceptionOnClose = true;
1467 
1468                try
1469                {
1470                    count++;
1471                    final URL manifestUrl = e.nextElement();
1472                    final String externalForm = manifestUrl.toExternalForm();
1473                    final String baseUrl = externalForm.substring( 0, externalForm.indexOf( "META-INF" ) );
1474                    manifestStream = manifestUrl.openStream();
1475                    final Manifest mf = new Manifest( manifestStream );
1476 
1477                    if ( this.isLoggable( Level.FINEST ) )
1478                    {
1479                        this.log( Level.FINEST, getMessage( "processing", externalForm ), null );
1480                    }
1481 
1482                    for ( Map.Entry<String, Attributes> entry : mf.getEntries().entrySet() )
1483                    {
1484                        for ( int i = SCHEMA_EXTENSIONS.length - 1; i >= 0; i-- )
1485                        {
1486                            if ( entry.getKey().toLowerCase().endsWith( '.' + SCHEMA_EXTENSIONS[i].toLowerCase() ) )
1487                            {
1488                                final URL schemaUrl = new URL( baseUrl + entry.getKey() );
1489                                resources.add( schemaUrl.toURI() );
1490 
1491                                if ( this.isLoggable( Level.FINEST ) )
1492                                {
1493                                    this.log( Level.FINEST, getMessage( "foundSchemaCandidate",
1494                                                                        schemaUrl.toExternalForm() ), null );
1495 
1496                                }
1497                            }
1498                        }
1499                    }
1500 
1501                    suppressExceptionOnClose = false;
1502                }
1503                finally
1504                {
1505                    try
1506                    {
1507                        if ( manifestStream != null )
1508                        {
1509                            manifestStream.close();
1510                        }
1511                    }
1512                    catch ( final IOException ex )
1513                    {
1514                        if ( suppressExceptionOnClose )
1515                        {
1516                            this.log( Level.SEVERE, getMessage( ex ), ex );
1517                        }
1518                        else
1519                        {
1520                            throw ex;
1521                        }
1522                    }
1523                }
1524            }
1525 
1526            if ( this.isLoggable( Level.FINE ) )
1527            {
1528                this.log( Level.FINE, getMessage( "contextReport", count, "META-INF/MANIFEST.MF",
1529                                                  System.currentTimeMillis() - t0 ), null );
1530 
1531            }
1532 
1533            this.cachedSchemaResources = new SoftReference<Set<URI>>( resources );
1534        }
1535 
1536        return resources;
1537    }
1538 
1539    private EntityResolver createEntityResolver( final Schemas schemas )
1540    {
1541        return new DefaultHandler()
1542        {
1543 
1544            @Override
1545            public InputSource resolveEntity( final String publicId, final String systemId )
1546                throws SAXException, IOException
1547            {
1548                if ( systemId == null )
1549                {
1550                    throw new NullPointerException( "systemId" );
1551                }
1552 
1553                InputSource schemaSource = null;
1554 
1555                try
1556                {
1557                    Schema s = null;
1558 
1559                    if ( schemas != null )
1560                    {
1561                        s = schemas.getSchemaBySystemId( systemId );
1562 
1563                        if ( s == null && publicId != null )
1564                        {
1565                            try
1566                            {
1567                                final List<Schema> schemasByPublicId =
1568                                    schemas.getSchemasByPublicId( new URI( publicId ) );
1569 
1570                                if ( schemasByPublicId.size() == 1 )
1571                                {
1572                                    s = schemasByPublicId.get( 0 );
1573                                }
1574                            }
1575                            catch ( final URISyntaxException e )
1576                            {
1577                                if ( isLoggable( Level.WARNING ) )
1578                                {
1579                                    log( Level.WARNING, getMessage( "unsupportedIdUri", publicId, getMessage( e ) ),
1580                                         null );
1581 
1582                                }
1583 
1584                                s = null;
1585                            }
1586                        }
1587                    }
1588 
1589                    if ( s != null )
1590                    {
1591                        schemaSource = new InputSource();
1592                        schemaSource.setPublicId( s.getPublicId() != null ? s.getPublicId() : publicId );
1593                        schemaSource.setSystemId( s.getSystemId() );
1594 
1595                        if ( s.getClasspathId() != null )
1596                        {
1597                            final URL resource = findResource( s.getClasspathId() );
1598 
1599                            if ( resource != null )
1600                            {
1601                                schemaSource.setSystemId( resource.toExternalForm() );
1602                            }
1603                            else if ( isLoggable( Level.WARNING ) )
1604                            {
1605                                log( Level.WARNING, getMessage( "resourceNotFound", s.getClasspathId() ), null );
1606                            }
1607                        }
1608 
1609                        if ( isLoggable( Level.FINEST ) )
1610                        {
1611                            log( Level.FINEST, getMessage( "resolutionInfo", publicId + ", " + systemId,
1612                                                           schemaSource.getPublicId() + ", "
1613                                                               + schemaSource.getSystemId() ), null );
1614 
1615                        }
1616                    }
1617 
1618                    if ( schemaSource == null )
1619                    {
1620                        final URI systemUri = new URI( systemId );
1621                        String schemaName = systemUri.getPath();
1622 
1623                        if ( schemaName != null )
1624                        {
1625                            final int lastIndexOfSlash = schemaName.lastIndexOf( '/' );
1626                            if ( lastIndexOfSlash != -1 && lastIndexOfSlash < schemaName.length() )
1627                            {
1628                                schemaName = schemaName.substring( lastIndexOfSlash + 1 );
1629                            }
1630 
1631                            for ( URI uri : getSchemaResources() )
1632                            {
1633                                if ( uri.getSchemeSpecificPart() != null
1634                                         && uri.getSchemeSpecificPart().endsWith( schemaName ) )
1635                                {
1636                                    schemaSource = new InputSource();
1637                                    schemaSource.setPublicId( publicId );
1638                                    schemaSource.setSystemId( uri.toASCIIString() );
1639 
1640                                    if ( isLoggable( Level.FINEST ) )
1641                                    {
1642                                        log( Level.FINEST, getMessage( "resolutionInfo", systemUri.toASCIIString(),
1643                                                                       schemaSource.getSystemId() ), null );
1644 
1645                                    }
1646 
1647                                    break;
1648                                }
1649                            }
1650                        }
1651                        else
1652                        {
1653                            if ( isLoggable( Level.WARNING ) )
1654                            {
1655                                log( Level.WARNING, getMessage( "unsupportedIdUri", systemId,
1656                                                                systemUri.toASCIIString() ), null );
1657 
1658                            }
1659 
1660                            schemaSource = null;
1661                        }
1662                    }
1663                }
1664                catch ( final URISyntaxException e )
1665                {
1666                    if ( isLoggable( Level.WARNING ) )
1667                    {
1668                        log( Level.WARNING, getMessage( "unsupportedIdUri", systemId, getMessage( e ) ), null );
1669                    }
1670 
1671                    schemaSource = null;
1672                }
1673                catch ( final ModelException e )
1674                {
1675                    String message = getMessage( e );
1676                    if ( message == null )
1677                    {
1678                        message = "";
1679                    }
1680                    else if ( message.length() > 0 )
1681                    {
1682                        message = " " + message;
1683                    }
1684 
1685                    String resource = "";
1686                    if ( publicId != null )
1687                    {
1688                        resource = publicId + ", ";
1689                    }
1690                    resource += systemId;
1691 
1692                    // JDK: As of JDK 6, "new IOException( message, cause )".
1693                    throw (IOException) new IOException( getMessage(
1694                        "failedResolving", resource, message ) ).initCause( e );
1695 
1696                }
1697 
1698                return schemaSource;
1699            }
1700 
1701        };
1702    }
1703 
1704    private LSResourceResolver createResourceResolver( final EntityResolver entityResolver )
1705    {
1706        if ( entityResolver == null )
1707        {
1708            throw new NullPointerException( "entityResolver" );
1709        }
1710 
1711        return new LSResourceResolver()
1712        {
1713 
1714            public LSInput resolveResource( final String type, final String namespaceURI, final String publicId,
1715                                            final String systemId, final String baseURI )
1716            {
1717                final String resolvePublicId = namespaceURI == null ? publicId : namespaceURI;
1718                final String resolveSystemId = systemId == null ? "" : systemId;
1719 
1720                try
1721                {
1722                    if ( XMLConstants.W3C_XML_SCHEMA_NS_URI.equals( type ) )
1723                    {
1724                        final InputSource schemaSource =
1725                            entityResolver.resolveEntity( resolvePublicId, resolveSystemId );
1726 
1727                        if ( schemaSource != null )
1728                        {
1729                            return new LSInput()
1730                            {
1731 
1732                                public Reader getCharacterStream()
1733                                {
1734                                    return schemaSource.getCharacterStream();
1735                                }
1736 
1737                                public void setCharacterStream( final Reader characterStream )
1738                                {
1739                                    if ( isLoggable( Level.WARNING ) )
1740                                    {
1741                                        log( Level.WARNING, getMessage(
1742                                             "unsupportedOperation", "setCharacterStream",
1743                                             DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1744 
1745                                    }
1746                                }
1747 
1748                                public InputStream getByteStream()
1749                                {
1750                                    return schemaSource.getByteStream();
1751                                }
1752 
1753                                public void setByteStream( final InputStream byteStream )
1754                                {
1755                                    if ( isLoggable( Level.WARNING ) )
1756                                    {
1757                                        log( Level.WARNING, getMessage(
1758                                             "unsupportedOperation", "setByteStream",
1759                                             DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1760 
1761                                    }
1762                                }
1763 
1764                                public String getStringData()
1765                                {
1766                                    return null;
1767                                }
1768 
1769                                public void setStringData( final String stringData )
1770                                {
1771                                    if ( isLoggable( Level.WARNING ) )
1772                                    {
1773                                        log( Level.WARNING, getMessage(
1774                                             "unsupportedOperation", "setStringData",
1775                                             DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1776 
1777                                    }
1778                                }
1779 
1780                                public String getSystemId()
1781                                {
1782                                    return schemaSource.getSystemId();
1783                                }
1784 
1785                                public void setSystemId( final String systemId )
1786                                {
1787                                    if ( isLoggable( Level.WARNING ) )
1788                                    {
1789                                        log( Level.WARNING, getMessage(
1790                                             "unsupportedOperation", "setSystemId",
1791                                             DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1792 
1793                                    }
1794                                }
1795 
1796                                public String getPublicId()
1797                                {
1798                                    return schemaSource.getPublicId();
1799                                }
1800 
1801                                public void setPublicId( final String publicId )
1802                                {
1803                                    if ( isLoggable( Level.WARNING ) )
1804                                    {
1805                                        log( Level.WARNING, getMessage(
1806                                             "unsupportedOperation", "setPublicId",
1807                                             DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1808 
1809                                    }
1810                                }
1811 
1812                                public String getBaseURI()
1813                                {
1814                                    return baseURI;
1815                                }
1816 
1817                                public void setBaseURI( final String baseURI )
1818                                {
1819                                    if ( isLoggable( Level.WARNING ) )
1820                                    {
1821                                        log( Level.WARNING, getMessage(
1822                                             "unsupportedOperation", "setBaseURI",
1823                                             DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1824 
1825                                    }
1826                                }
1827 
1828                                public String getEncoding()
1829                                {
1830                                    return schemaSource.getEncoding();
1831                                }
1832 
1833                                public void setEncoding( final String encoding )
1834                                {
1835                                    if ( isLoggable( Level.WARNING ) )
1836                                    {
1837                                        log( Level.WARNING, getMessage(
1838                                             "unsupportedOperation", "setEncoding",
1839                                             DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1840 
1841                                    }
1842                                }
1843 
1844                                public boolean getCertifiedText()
1845                                {
1846                                    return false;
1847                                }
1848 
1849                                public void setCertifiedText( final boolean certifiedText )
1850                                {
1851                                    if ( isLoggable( Level.WARNING ) )
1852                                    {
1853                                        log( Level.WARNING, getMessage(
1854                                             "unsupportedOperation", "setCertifiedText",
1855                                             DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1856 
1857                                    }
1858                                }
1859 
1860                            };
1861                        }
1862 
1863                    }
1864                    else if ( isLoggable( Level.WARNING ) )
1865                    {
1866                        log( Level.WARNING, getMessage( "unsupportedResourceType", type ), null );
1867                    }
1868                }
1869                catch ( final SAXException e )
1870                {
1871                    String message = getMessage( e );
1872                    if ( message == null && e.getException() != null )
1873                    {
1874                        message = getMessage( e.getException() );
1875                    }
1876                    if ( message == null )
1877                    {
1878                        message = "";
1879                    }
1880                    else if ( message.length() > 0 )
1881                    {
1882                        message = " " + message;
1883                    }
1884 
1885                    String resource = "";
1886                    if ( resolvePublicId != null )
1887                    {
1888                        resource = resolvePublicId + ", ";
1889                    }
1890                    resource += resolveSystemId;
1891 
1892                    if ( isLoggable( Level.SEVERE ) )
1893                    {
1894                        log( Level.SEVERE, getMessage( "failedResolving", resource, message ), e );
1895                    }
1896                }
1897                catch ( final IOException e )
1898                {
1899                    String message = getMessage( e );
1900                    if ( message == null )
1901                    {
1902                        message = "";
1903                    }
1904                    else if ( message.length() > 0 )
1905                    {
1906                        message = " " + message;
1907                    }
1908 
1909                    String resource = "";
1910                    if ( resolvePublicId != null )
1911                    {
1912                        resource = resolvePublicId + ", ";
1913                    }
1914                    resource += resolveSystemId;
1915 
1916                    if ( isLoggable( Level.SEVERE ) )
1917                    {
1918                        log( Level.SEVERE, getMessage( "failedResolving", resource, message ), e );
1919                    }
1920                }
1921 
1922                return null;
1923            }
1924 
1925        };
1926    }
1927 
1928    private javax.xml.validation.Schema createSchema( final Schemas schemas, final EntityResolver entityResolver,
1929                                                      final LSResourceResolver resourceResolver, final String model,
1930                                                      final URI publicId ) throws ModelException
1931    {
1932        if ( entityResolver == null )
1933        {
1934            throw new NullPointerException( "entityResolver" );
1935        }
1936        if ( model != null && publicId != null )
1937        {
1938            throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
1939        }
1940 
1941        try
1942        {
1943            final long t0 = System.currentTimeMillis();
1944            final SchemaFactory f = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
1945            final List<Source> sources = new ArrayList<Source>( schemas != null ? schemas.getSchema().size() : 0 );
1946 
1947            if ( schemas != null )
1948            {
1949                for ( Schema s : schemas.getSchema() )
1950                {
1951                    final InputSource inputSource = entityResolver.resolveEntity( s.getPublicId(), s.getSystemId() );
1952 
1953                    if ( inputSource != null )
1954                    {
1955                        sources.add( new SAXSource( inputSource ) );
1956                    }
1957                }
1958            }
1959 
1960            if ( sources.isEmpty() )
1961            {
1962                if ( model != null )
1963                {
1964                    throw new ModelException( getMessage( "missingSchemasForModel", model ) );
1965                }
1966                if ( publicId != null )
1967                {
1968                    throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
1969                }
1970            }
1971 
1972            f.setResourceResolver( resourceResolver );
1973            f.setErrorHandler( new ErrorHandler()
1974            {
1975                // See http://java.net/jira/browse/JAXP-66
1976 
1977                public void warning( final SAXParseException e ) throws SAXException
1978                {
1979                    String message = getMessage( e );
1980                    if ( message == null && e.getException() != null )
1981                    {
1982                        message = getMessage( e.getException() );
1983                    }
1984 
1985                    if ( isLoggable( Level.WARNING ) )
1986                    {
1987                        log( Level.WARNING, message, e );
1988                    }
1989                }
1990 
1991                public void error( final SAXParseException e ) throws SAXException
1992                {
1993                    throw e;
1994                }
1995 
1996                public void fatalError( final SAXParseException e ) throws SAXException
1997                {
1998                    throw e;
1999                }
2000 
2001            } );
2002 
2003            final javax.xml.validation.Schema schema = f.newSchema( sources.toArray( new Source[ sources.size() ] ) );
2004 
2005            if ( this.isLoggable( Level.FINE ) )
2006            {
2007                final StringBuilder schemaInfo = new StringBuilder( sources.size() * 50 );
2008 
2009                for ( Source s : sources )
2010                {
2011                    schemaInfo.append( ", " ).append( s.getSystemId() );
2012                }
2013 
2014                this.log( Level.FINE, getMessage( "creatingSchema", schemaInfo.substring( 2 ),
2015                                                  System.currentTimeMillis() - t0 ), null );
2016 
2017            }
2018 
2019            return schema;
2020        }
2021        catch ( final IOException e )
2022        {
2023            throw new ModelException( getMessage( e ), e );
2024        }
2025        catch ( final SAXException e )
2026        {
2027            String message = getMessage( e );
2028            if ( message == null && e.getException() != null )
2029            {
2030                message = getMessage( e.getException() );
2031            }
2032 
2033            throw new ModelException( message, e );
2034        }
2035    }
2036 
2037    private JAXBContext createContext( final Schemas schemas, final String model, final URI publicId )
2038        throws ModelException
2039    {
2040        if ( model != null && publicId != null )
2041        {
2042            throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
2043        }
2044 
2045        try
2046        {
2047            StringBuilder packageNames = null;
2048            final long t0 = System.currentTimeMillis();
2049 
2050            if ( schemas != null )
2051            {
2052                packageNames = new StringBuilder( schemas.getSchema().size() * 25 );
2053 
2054                for ( Schema schema : schemas.getSchema() )
2055                {
2056                    if ( schema.getContextId() != null )
2057                    {
2058                        packageNames.append( ':' ).append( schema.getContextId() );
2059                    }
2060                }
2061            }
2062 
2063            if ( packageNames == null || packageNames.length() == 0 )
2064            {
2065                if ( model != null )
2066                {
2067                    throw new ModelException( getMessage( "missingSchemasForModel", model ) );
2068                }
2069                if ( publicId != null )
2070                {
2071                    throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
2072                }
2073            }
2074 
2075            final JAXBContext context = JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() );
2076 
2077            if ( this.isLoggable( Level.FINE ) )
2078            {
2079                this.log( Level.FINE, getMessage( "creatingContext", packageNames.substring( 1 ),
2080                                                  System.currentTimeMillis() - t0 ), null );
2081            }
2082 
2083            return context;
2084        }
2085        catch ( final JAXBException e )
2086        {
2087            String message = getMessage( e );
2088            if ( message == null && e.getLinkedException() != null )
2089            {
2090                message = getMessage( e.getLinkedException() );
2091            }
2092 
2093            throw new ModelException( message, e );
2094        }
2095    }
2096 
2097    private Marshaller createMarshaller( final Schemas schemas, final Services services, final String model,
2098                                         final URI publicId ) throws ModelException
2099    {
2100        if ( model != null && publicId != null )
2101        {
2102            throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
2103        }
2104 
2105        try
2106        {
2107            StringBuilder packageNames = null;
2108            StringBuilder schemaLocation = null;
2109            final long t0 = System.currentTimeMillis();
2110 
2111            if ( schemas != null )
2112            {
2113                packageNames = new StringBuilder( schemas.getSchema().size() * 25 );
2114                schemaLocation = new StringBuilder( schemas.getSchema().size() * 50 );
2115 
2116                for ( Schema schema : schemas.getSchema() )
2117                {
2118                    if ( schema.getContextId() != null )
2119                    {
2120                        packageNames.append( ':' ).append( schema.getContextId() );
2121                    }
2122                    if ( schema.getPublicId() != null && schema.getSystemId() != null )
2123                    {
2124                        schemaLocation.append( ' ' ).append( schema.getPublicId() ).append( ' ' ).
2125                            append( schema.getSystemId() );
2126 
2127                    }
2128                }
2129            }
2130 
2131            if ( packageNames == null || packageNames.length() == 0 )
2132            {
2133                if ( model != null )
2134                {
2135                    throw new ModelException( getMessage( "missingSchemasForModel", model ) );
2136                }
2137                if ( publicId != null )
2138                {
2139                    throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
2140                }
2141            }
2142 
2143            final Marshaller m =
2144                JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() ).createMarshaller();
2145 
2146            if ( schemaLocation != null && schemaLocation.length() != 0 )
2147            {
2148                m.setProperty( Marshaller.JAXB_SCHEMA_LOCATION, schemaLocation.substring( 1 ) );
2149            }
2150 
2151            MarshallerListenerList listenerList = null;
2152 
2153            if ( services != null )
2154            {
2155                for ( Service service : services.getServices( MARSHALLER_LISTENER_SERVICE ) )
2156                {
2157                    if ( listenerList == null )
2158                    {
2159                        listenerList = new MarshallerListenerList();
2160                    }
2161 
2162                    listenerList.getListeners().add( this.createServiceObject( service, Marshaller.Listener.class ) );
2163                }
2164            }
2165 
2166            if ( listenerList != null )
2167            {
2168                m.setListener( listenerList );
2169            }
2170 
2171            if ( this.isLoggable( Level.FINE ) )
2172            {
2173                if ( listenerList == null )
2174                {
2175                    this.log( Level.FINE, getMessage( "creatingMarshaller", packageNames.substring( 1 ),
2176                                                      schemaLocation.substring( 1 ),
2177                                                      System.currentTimeMillis() - t0 ), null );
2178 
2179                }
2180                else
2181                {
2182                    final StringBuilder b = new StringBuilder( listenerList.getListeners().size() * 100 );
2183 
2184                    for ( int i = 0, s0 = listenerList.getListeners().size(); i < s0; i++ )
2185                    {
2186                        b.append( ',' ).append( listenerList.getListeners().get( i ) );
2187                    }
2188 
2189                    this.log( Level.FINE, getMessage( "creatingMarshallerWithListeners", packageNames.substring( 1 ),
2190                                                      schemaLocation.substring( 1 ), b.substring( 1 ),
2191                                                      System.currentTimeMillis() - t0 ), null );
2192 
2193                }
2194            }
2195 
2196            return m;
2197        }
2198        catch ( final JAXBException e )
2199        {
2200            String message = getMessage( e );
2201            if ( message == null && e.getLinkedException() != null )
2202            {
2203                message = getMessage( e.getLinkedException() );
2204            }
2205 
2206            throw new ModelException( message, e );
2207        }
2208    }
2209 
2210    private Unmarshaller createUnmarshaller( final Schemas schemas, final Services services, final String model,
2211                                             final URI publicId ) throws ModelException
2212    {
2213        if ( model != null && publicId != null )
2214        {
2215            throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
2216        }
2217 
2218        try
2219        {
2220            StringBuilder packageNames = null;
2221            final long t0 = System.currentTimeMillis();
2222 
2223            if ( schemas != null )
2224            {
2225                packageNames = new StringBuilder( schemas.getSchema().size() * 25 );
2226 
2227                for ( Schema schema : schemas.getSchema() )
2228                {
2229                    if ( schema.getContextId() != null )
2230                    {
2231                        packageNames.append( ':' ).append( schema.getContextId() );
2232                    }
2233                }
2234            }
2235 
2236            if ( packageNames == null || packageNames.length() == 0 )
2237            {
2238                if ( model != null )
2239                {
2240                    throw new ModelException( getMessage( "missingSchemasForModel", model ) );
2241                }
2242                if ( publicId != null )
2243                {
2244                    throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
2245                }
2246            }
2247 
2248            final Unmarshaller u =
2249                JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() ).createUnmarshaller();
2250 
2251            UnmarshallerListenerList listenerList = null;
2252 
2253            if ( services != null )
2254            {
2255                for ( Service service : services.getServices( UNMARSHALLER_LISTENER_SERVICE ) )
2256                {
2257                    if ( listenerList == null )
2258                    {
2259                        listenerList = new UnmarshallerListenerList();
2260                    }
2261 
2262                    listenerList.getListeners().add( this.createServiceObject( service, Unmarshaller.Listener.class ) );
2263                }
2264            }
2265 
2266            if ( listenerList != null )
2267            {
2268                u.setListener( listenerList );
2269            }
2270 
2271            if ( this.isLoggable( Level.FINE ) )
2272            {
2273                if ( listenerList == null )
2274                {
2275                    this.log( Level.FINE, getMessage( "creatingUnmarshaller", packageNames.substring( 1 ),
2276                                                      System.currentTimeMillis() - t0 ), null );
2277 
2278                }
2279                else
2280                {
2281                    final StringBuilder b = new StringBuilder( listenerList.getListeners().size() * 100 );
2282 
2283                    for ( int i = 0, s0 = listenerList.getListeners().size(); i < s0; i++ )
2284                    {
2285                        b.append( ',' ).append( listenerList.getListeners().get( i ) );
2286                    }
2287 
2288                    this.log( Level.FINE, getMessage( "creatingUnmarshallerWithListeners",
2289                                                      packageNames.substring( 1 ), b.substring( 1 ),
2290                                                      System.currentTimeMillis() - t0 ), null );
2291 
2292                }
2293            }
2294 
2295            return u;
2296        }
2297        catch ( final JAXBException e )
2298        {
2299            String message = getMessage( e );
2300            if ( message == null && e.getLinkedException() != null )
2301            {
2302                message = getMessage( e.getLinkedException() );
2303            }
2304 
2305            throw new ModelException( message, e );
2306        }
2307    }
2308 
2309    private static String getMessage( final String key, final Object... arguments )
2310    {
2311        return MessageFormat.format( ResourceBundle.getBundle(
2312            DefaultModelContext.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
2313 
2314    }
2315 
2316    private static String getMessage( final Throwable t )
2317    {
2318        return t != null
2319                   ? t.getMessage() != null && t.getMessage().trim().length() > 0
2320                         ? t.getMessage()
2321                         : getMessage( t.getCause() )
2322                   : null;
2323 
2324    }
2325 
2326}
2327 
2328/**
2329 * {@code ErrorHandler} collecting {@code ModelValidationReport} details.
2330 *
2331 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
2332 * @version $JOMC: DefaultModelContext.java 4939 2014-03-25 03:47:18Z schulte $
2333 */
2334class ModelErrorHandler extends DefaultHandler
2335{
2336 
2337    /** The context of the instance. */
2338    private ModelContext context;
2339 
2340    /** The report of the instance. */
2341    private ModelValidationReport report;
2342 
2343    /**
2344     * Creates a new {@code ModelErrorHandler} instance taking a context.
2345     *
2346     * @param context The context of the instance.
2347     */
2348    ModelErrorHandler( final ModelContext context )
2349    {
2350        this( context, null );
2351    }
2352 
2353    /**
2354     * Creates a new {@code ModelErrorHandler} instance taking a report to use for collecting validation events.
2355     *
2356     * @param context The context of the instance.
2357     * @param report A report to use for collecting validation events.
2358     */
2359    ModelErrorHandler( final ModelContext context, final ModelValidationReport report )
2360    {
2361        super();
2362        this.context = context;
2363        this.report = report;
2364    }
2365 
2366    /**
2367     * Gets the report of the instance.
2368     *
2369     * @return The report of the instance.
2370     */
2371    public ModelValidationReport getReport()
2372    {
2373        if ( this.report == null )
2374        {
2375            this.report = new ModelValidationReport();
2376        }
2377 
2378        return this.report;
2379    }
2380 
2381    @Override
2382    public void warning( final SAXParseException exception ) throws SAXException
2383    {
2384        String message = getMessage( exception );
2385        if ( message == null && exception.getException() != null )
2386        {
2387            message = getMessage( exception.getException() );
2388        }
2389 
2390        if ( this.context != null && this.context.isLoggable( Level.FINE ) )
2391        {
2392            this.context.log( Level.FINE, message, exception );
2393        }
2394 
2395        this.getReport().getDetails().add( new ModelValidationReport.Detail(
2396            "W3C XML 1.0 Recommendation - Warning condition", Level.WARNING, message, null ) );
2397 
2398    }
2399 
2400    @Override
2401    public void error( final SAXParseException exception ) throws SAXException
2402    {
2403        String message = getMessage( exception );
2404        if ( message == null && exception.getException() != null )
2405        {
2406            message = getMessage( exception.getException() );
2407        }
2408 
2409        if ( this.context != null && this.context.isLoggable( Level.FINE ) )
2410        {
2411            this.context.log( Level.FINE, message, exception );
2412        }
2413 
2414        this.getReport().getDetails().add( new ModelValidationReport.Detail(
2415            "W3C XML 1.0 Recommendation - Section 1.2 - Error", Level.SEVERE, message, null ) );
2416 
2417    }
2418 
2419    @Override
2420    public void fatalError( final SAXParseException exception ) throws SAXException
2421    {
2422        String message = getMessage( exception );
2423        if ( message == null && exception.getException() != null )
2424        {
2425            message = getMessage( exception.getException() );
2426        }
2427 
2428        if ( this.context != null && this.context.isLoggable( Level.FINE ) )
2429        {
2430            this.context.log( Level.FINE, message, exception );
2431        }
2432 
2433        this.getReport().getDetails().add( new ModelValidationReport.Detail(
2434            "W3C XML 1.0 Recommendation - Section 1.2 - Fatal Error", Level.SEVERE, message, null ) );
2435 
2436    }
2437 
2438    private static String getMessage( final Throwable t )
2439    {
2440        return t != null
2441                   ? t.getMessage() != null && t.getMessage().trim().length() > 0
2442                         ? t.getMessage()
2443                         : getMessage( t.getCause() )
2444                   : null;
2445 
2446    }
2447 
2448}
2449 
2450/**
2451 * List of {@code Marshaller.Listener}s.
2452 *
2453 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
2454 * @version $JOMC: DefaultModelContext.java 4939 2014-03-25 03:47:18Z schulte $
2455 * @since 1.2
2456 */
2457class MarshallerListenerList extends Marshaller.Listener
2458{
2459 
2460    /** The {@code Marshaller.Listener}s of the instance. */
2461    private List<Marshaller.Listener> listeners;
2462 
2463    /** Creates a new {@code MarshallerListenerList} instance. */
2464    MarshallerListenerList()
2465    {
2466        super();
2467    }
2468 
2469    /**
2470     * Gets the listeners of the instance.
2471     * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
2472     * to the returned list will be present inside the object. This is why there is no {@code set} method for the
2473     * listeners property.</p>
2474     *
2475     * @return The list of listeners of the instance.
2476     */
2477    List<Marshaller.Listener> getListeners()
2478    {
2479        if ( this.listeners == null )
2480        {
2481            this.listeners = new ArrayList<Marshaller.Listener>();
2482        }
2483 
2484        return this.listeners;
2485    }
2486 
2487    @Override
2488    public void beforeMarshal( final Object source )
2489    {
2490        for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
2491        {
2492            this.getListeners().get( i ).beforeMarshal( source );
2493        }
2494    }
2495 
2496    @Override
2497    public void afterMarshal( final Object source )
2498    {
2499        for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
2500        {
2501            this.getListeners().get( i ).afterMarshal( source );
2502        }
2503    }
2504 
2505}
2506 
2507/**
2508 * List of {@code Unmarshaller.Listener}s.
2509 *
2510 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
2511 * @version $JOMC: DefaultModelContext.java 4939 2014-03-25 03:47:18Z schulte $
2512 * @since 1.2
2513 */
2514class UnmarshallerListenerList extends Unmarshaller.Listener
2515{
2516 
2517    /** The {@code Unmarshaller.Listener}s of the instance. */
2518    private List<Unmarshaller.Listener> listeners;
2519 
2520    /** Creates a new {@code UnmarshallerListenerList} instance. */
2521    UnmarshallerListenerList()
2522    {
2523        super();
2524    }
2525 
2526    /**
2527     * Gets the listeners of the instance.
2528     * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
2529     * to the returned list will be present inside the object. This is why there is no {@code set} method for the
2530     * listeners property.</p>
2531     *
2532     * @return The list of listeners of the instance.
2533     */
2534    List<Unmarshaller.Listener> getListeners()
2535    {
2536        if ( this.listeners == null )
2537        {
2538            this.listeners = new ArrayList<Unmarshaller.Listener>();
2539        }
2540 
2541        return this.listeners;
2542    }
2543 
2544    @Override
2545    public void beforeUnmarshal( final Object target, final Object parent )
2546    {
2547        for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
2548        {
2549            this.getListeners().get( i ).beforeUnmarshal( target, parent );
2550        }
2551    }
2552 
2553    @Override
2554    public void afterUnmarshal( final Object target, final Object parent )
2555    {
2556        for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
2557        {
2558            this.getListeners().get( i ).afterUnmarshal( target, parent );
2559        }
2560    }
2561 
2562}

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