EMMA Coverage Report (generated Fri Feb 21 04:03:47 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)81%  (3745/4619)81%  (648.3/801)

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

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