EMMA Coverage Report (generated Thu Jan 03 04:54:40 CET 2013)
[all classes][org.jomc.modlet]

COVERAGE SUMMARY FOR SOURCE FILE [DefaultModelContext.java]

nameclass, %method, %block, %line, %
DefaultModelContext.java100% (9/9)95%  (83/87)81%  (3626/4487)80%  (618.1/768)

COVERAGE BREAKDOWN BY CLASS AND METHOD

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

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