~vcs-imports/xena/trunk

« back to all changes in this revision

Viewing changes to ext/src/xerces-2_9_1/src/org/apache/xerces/jaxp/validation/XMLSchemaFactory.java

  • Committer: matthewoliver
  • Date: 2009-12-10 03:18:07 UTC
  • Revision ID: vcs-imports@canonical.com-20091210031807-l086qguzdlljtkl9
Merged Xena Testing into Xena Stable for the Xena 5 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
 
3
 * contributor license agreements.  See the NOTICE file distributed with
 
4
 * this work for additional information regarding copyright ownership.
 
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
 
6
 * (the "License"); you may not use this file except in compliance with
 
7
 * the License.  You may obtain a copy of the License at
 
8
 * 
 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
 
10
 * 
 
11
 * Unless required by applicable law or agreed to in writing, software
 
12
 * distributed under the License is distributed on an "AS IS" BASIS,
 
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
 * See the License for the specific language governing permissions and
 
15
 * limitations under the License.
 
16
 */
 
17
 
 
18
package org.apache.xerces.jaxp.validation;
 
19
 
 
20
import java.io.IOException;
 
21
import java.io.InputStream;
 
22
import java.io.Reader;
 
23
import java.util.Locale;
 
24
 
 
25
import javax.xml.XMLConstants;
 
26
import javax.xml.transform.Source;
 
27
import javax.xml.transform.dom.DOMSource;
 
28
import javax.xml.transform.sax.SAXSource;
 
29
import javax.xml.transform.stream.StreamSource;
 
30
import javax.xml.validation.Schema;
 
31
import javax.xml.validation.SchemaFactory;
 
32
 
 
33
import org.apache.xerces.impl.Constants;
 
34
import org.apache.xerces.impl.xs.XMLSchemaLoader;
 
35
import org.apache.xerces.util.DOMEntityResolverWrapper;
 
36
import org.apache.xerces.util.DOMInputSource;
 
37
import org.apache.xerces.util.ErrorHandlerWrapper;
 
38
import org.apache.xerces.util.SAXInputSource;
 
39
import org.apache.xerces.util.SAXMessageFormatter;
 
40
import org.apache.xerces.util.SecurityManager;
 
41
import org.apache.xerces.util.XMLGrammarPoolImpl;
 
42
import org.apache.xerces.xni.XNIException;
 
43
import org.apache.xerces.xni.grammars.Grammar;
 
44
import org.apache.xerces.xni.grammars.XMLGrammarDescription;
 
45
import org.apache.xerces.xni.grammars.XMLGrammarPool;
 
46
import org.apache.xerces.xni.parser.XMLConfigurationException;
 
47
import org.apache.xerces.xni.parser.XMLInputSource;
 
48
import org.w3c.dom.Node;
 
49
import org.w3c.dom.ls.LSResourceResolver;
 
50
import org.xml.sax.ErrorHandler;
 
51
import org.xml.sax.InputSource;
 
52
import org.xml.sax.SAXException;
 
53
import org.xml.sax.SAXNotRecognizedException;
 
54
import org.xml.sax.SAXNotSupportedException;
 
55
import org.xml.sax.SAXParseException;
 
56
 
 
57
/**
 
58
 * {@link SchemaFactory} for XML Schema.
 
59
 *
 
60
 * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
 
61
 * @version $Id: XMLSchemaFactory.java,v 1.2 2009/12/10 03:18:25 matthewoliver Exp $
 
62
 */
 
63
public final class XMLSchemaFactory extends SchemaFactory {
 
64
    
 
65
    // feature identifiers
 
66
    
 
67
    /** Feature identifier: schema full checking. */
 
68
    private static final String SCHEMA_FULL_CHECKING =
 
69
        Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING;
 
70
    
 
71
    /** Feature identifier: use grammar pool only. */
 
72
    private static final String USE_GRAMMAR_POOL_ONLY =
 
73
        Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;
 
74
    
 
75
    // property identifiers
 
76
    
 
77
    /** Property identifier: grammar pool. */
 
78
    private static final String XMLGRAMMAR_POOL =
 
79
        Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
 
80
    
 
81
    /** Property identifier: SecurityManager. */
 
82
    private static final String SECURITY_MANAGER =
 
83
        Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
 
84
    
 
85
    //
 
86
    // Data
 
87
    //
 
88
    
 
89
    /** The XMLSchemaLoader */
 
90
    private final XMLSchemaLoader fXMLSchemaLoader = new XMLSchemaLoader();
 
91
    
 
92
    /** User-specified ErrorHandler; can be null. */
 
93
    private ErrorHandler fErrorHandler;
 
94
    
 
95
    /** The LSResrouceResolver */
 
96
    private LSResourceResolver fLSResourceResolver;
 
97
    
 
98
    /** The DOMEntityResolverWrapper */
 
99
    private final DOMEntityResolverWrapper fDOMEntityResolverWrapper;
 
100
    
 
101
    /** The ErrorHandlerWrapper */
 
102
    private final ErrorHandlerWrapper fErrorHandlerWrapper;
 
103
    
 
104
    /** The SecurityManager. */
 
105
    private SecurityManager fSecurityManager;
 
106
    
 
107
    /** The container for the real grammar pool. */ 
 
108
    private final XMLGrammarPoolWrapper fXMLGrammarPoolWrapper;
 
109
    
 
110
    /** Whether or not to allow new schemas to be added to the grammar pool */
 
111
    private boolean fUseGrammarPoolOnly;
 
112
    
 
113
    public XMLSchemaFactory() {
 
114
        fErrorHandlerWrapper = new ErrorHandlerWrapper(DraconianErrorHandler.getInstance());
 
115
        fDOMEntityResolverWrapper = new DOMEntityResolverWrapper();
 
116
        fXMLGrammarPoolWrapper = new XMLGrammarPoolWrapper();
 
117
        fXMLSchemaLoader.setFeature(SCHEMA_FULL_CHECKING, true);
 
118
        fXMLSchemaLoader.setProperty(XMLGRAMMAR_POOL, fXMLGrammarPoolWrapper);
 
119
        fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper);
 
120
        fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper);
 
121
        fUseGrammarPoolOnly = true;
 
122
    }
 
123
    
 
124
    /**
 
125
     * <p>Is specified schema supported by this <code>SchemaFactory</code>?</p>
 
126
     *
 
127
     * @param schemaLanguage Specifies the schema language which the returned <code>SchemaFactory</code> will understand.
 
128
     *    <code>schemaLanguage</code> must specify a <a href="#schemaLanguage">valid</a> schema language.
 
129
     *
 
130
     * @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>.
 
131
     *
 
132
     * @throws NullPointerException If <code>schemaLanguage</code> is <code>null</code>.
 
133
     * @throws IllegalArgumentException If <code>schemaLanguage.length() == 0</code>
 
134
     *   or <code>schemaLanguage</code> does not specify a <a href="#schemaLanguage">valid</a> schema language.
 
135
     */
 
136
    public boolean isSchemaLanguageSupported(String schemaLanguage) {
 
137
        if (schemaLanguage == null) {
 
138
            throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(), 
 
139
                    "SchemaLanguageNull", null));
 
140
        }
 
141
        if (schemaLanguage.length() == 0) {
 
142
            throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(), 
 
143
                    "SchemaLanguageLengthZero", null));
 
144
        }
 
145
        // only W3C XML Schema 1.0 is supported 
 
146
        return schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI);
 
147
    }
 
148
    
 
149
    public LSResourceResolver getResourceResolver() {
 
150
        return fLSResourceResolver;
 
151
    }
 
152
    
 
153
    public void setResourceResolver(LSResourceResolver resourceResolver) {
 
154
        fLSResourceResolver = resourceResolver;
 
155
        fDOMEntityResolverWrapper.setEntityResolver(resourceResolver);
 
156
        fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper);
 
157
    }
 
158
    
 
159
    public ErrorHandler getErrorHandler() {
 
160
        return fErrorHandler;
 
161
    }
 
162
    
 
163
    public void setErrorHandler(ErrorHandler errorHandler) {
 
164
        fErrorHandler = errorHandler;
 
165
        fErrorHandlerWrapper.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance());
 
166
        fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper);
 
167
    }  
 
168
    
 
169
    public Schema newSchema( Source[] schemas ) throws SAXException {
 
170
        
 
171
        // this will let the loader store parsed Grammars into the pool.
 
172
        XMLGrammarPoolImplExtension pool = new XMLGrammarPoolImplExtension();
 
173
        fXMLGrammarPoolWrapper.setGrammarPool(pool);
 
174
        
 
175
        XMLInputSource[] xmlInputSources = new XMLInputSource[schemas.length];
 
176
        InputStream inputStream;
 
177
        Reader reader;
 
178
        for( int i=0; i<schemas.length; i++ ) {
 
179
            Source source = schemas[i];
 
180
            if (source instanceof StreamSource) {
 
181
                StreamSource streamSource = (StreamSource) source;
 
182
                String publicId = streamSource.getPublicId();
 
183
                String systemId = streamSource.getSystemId();
 
184
                inputStream = streamSource.getInputStream();
 
185
                reader = streamSource.getReader();
 
186
                xmlInputSources[i] = new XMLInputSource(publicId, systemId, null);
 
187
                xmlInputSources[i].setByteStream(inputStream);
 
188
                xmlInputSources[i].setCharacterStream(reader);
 
189
            }
 
190
            else if (source instanceof SAXSource) {
 
191
                SAXSource saxSource = (SAXSource) source;
 
192
                InputSource inputSource = saxSource.getInputSource();
 
193
                if (inputSource == null) {
 
194
                    throw new SAXException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(), 
 
195
                            "SAXSourceNullInputSource", null));
 
196
                }
 
197
                xmlInputSources[i] = new SAXInputSource(saxSource.getXMLReader(), inputSource);
 
198
            }
 
199
            else if (source instanceof DOMSource) {
 
200
                DOMSource domSource = (DOMSource) source;
 
201
                Node node = domSource.getNode();
 
202
                String systemID = domSource.getSystemId();          
 
203
                xmlInputSources[i] = new DOMInputSource(node, systemID);
 
204
            }
 
205
            else if (source == null) {
 
206
                throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(), 
 
207
                        "SchemaSourceArrayMemberNull", null));
 
208
            }
 
209
            else {
 
210
                throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(), 
 
211
                        "SchemaFactorySourceUnrecognized", 
 
212
                        new Object [] {source.getClass().getName()}));
 
213
            }
 
214
        }
 
215
        
 
216
        try {
 
217
            fXMLSchemaLoader.loadGrammar(xmlInputSources);
 
218
        } 
 
219
        catch (XNIException e) {
 
220
            // this should have been reported to users already.
 
221
            throw Util.toSAXException(e);
 
222
        } 
 
223
        catch (IOException e) {
 
224
            // this hasn't been reported, so do so now.
 
225
            SAXParseException se = new SAXParseException(e.getMessage(),null,e);
 
226
            if (fErrorHandler != null) {
 
227
                fErrorHandler.error(se);
 
228
            }
 
229
            throw se; // and we must throw it.
 
230
        }
 
231
        
 
232
        // Clear reference to grammar pool.
 
233
        fXMLGrammarPoolWrapper.setGrammarPool(null);
 
234
        
 
235
        // Select Schema implementation based on grammar count.
 
236
        final int grammarCount = pool.getGrammarCount();
 
237
        AbstractXMLSchema schema = null;
 
238
        if (fUseGrammarPoolOnly) {
 
239
            if (grammarCount > 1) {
 
240
                schema = new XMLSchema(new ReadOnlyGrammarPool(pool));
 
241
            }
 
242
            else if (grammarCount == 1) {
 
243
                Grammar[] grammars = pool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA);
 
244
                schema = new SimpleXMLSchema(grammars[0]);
 
245
            }
 
246
            else {
 
247
                schema = new EmptyXMLSchema();
 
248
            }
 
249
        }
 
250
        else {
 
251
            schema = new XMLSchema(new ReadOnlyGrammarPool(pool), false);
 
252
        }
 
253
        propagateFeatures(schema);
 
254
        return schema;
 
255
    }
 
256
    
 
257
    public Schema newSchema() throws SAXException {
 
258
        /*
 
259
         * It would make sense to return an EmptyXMLSchema object here, if
 
260
         * fUseGrammarPoolOnly is set to true. However, because the default
 
261
         * value of this feature is true, doing so would change the default
 
262
         * behaviour of this method. Thus, we return a WeakReferenceXMLSchema
 
263
         * regardless of the value of fUseGrammarPoolOnly. -PM
 
264
         */
 
265
        
 
266
        // Use a Schema that uses the system id as the equality source.
 
267
        AbstractXMLSchema schema = new WeakReferenceXMLSchema();
 
268
        propagateFeatures(schema);
 
269
        return schema;
 
270
    }
 
271
    
 
272
    public boolean getFeature(String name) 
 
273
        throws SAXNotRecognizedException, SAXNotSupportedException {
 
274
        if (name == null) {
 
275
            throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(), 
 
276
                    "FeatureNameNull", null));
 
277
        }
 
278
        if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
 
279
            return (fSecurityManager != null);
 
280
        }
 
281
        else if (name.equals(USE_GRAMMAR_POOL_ONLY)) {
 
282
            return fUseGrammarPoolOnly;
 
283
        }
 
284
        try {
 
285
            return fXMLSchemaLoader.getFeature(name);
 
286
        }
 
287
        catch (XMLConfigurationException e) {
 
288
            String identifier = e.getIdentifier();
 
289
            if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
 
290
                throw new SAXNotRecognizedException(
 
291
                        SAXMessageFormatter.formatMessage(Locale.getDefault(), 
 
292
                        "feature-not-recognized", new Object [] {identifier}));
 
293
            }
 
294
            else {
 
295
                throw new SAXNotSupportedException(
 
296
                        SAXMessageFormatter.formatMessage(Locale.getDefault(), 
 
297
                        "feature-not-supported", new Object [] {identifier}));
 
298
            }
 
299
        }
 
300
    }
 
301
    
 
302
    public Object getProperty(String name) 
 
303
        throws SAXNotRecognizedException, SAXNotSupportedException {
 
304
        if (name == null) {
 
305
            throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(), 
 
306
                    "ProperyNameNull", null));
 
307
        }
 
308
        if (name.equals(SECURITY_MANAGER)) {
 
309
            return fSecurityManager;
 
310
        }
 
311
        else if (name.equals(XMLGRAMMAR_POOL)) {
 
312
            throw new SAXNotSupportedException(
 
313
                    SAXMessageFormatter.formatMessage(Locale.getDefault(), 
 
314
                    "property-not-supported", new Object [] {name}));
 
315
        }
 
316
        try {
 
317
            return fXMLSchemaLoader.getProperty(name);
 
318
        }
 
319
        catch (XMLConfigurationException e) {
 
320
            String identifier = e.getIdentifier();
 
321
            if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
 
322
                throw new SAXNotRecognizedException(
 
323
                        SAXMessageFormatter.formatMessage(Locale.getDefault(), 
 
324
                        "property-not-recognized", new Object [] {identifier}));
 
325
            }
 
326
            else {
 
327
                throw new SAXNotSupportedException(
 
328
                        SAXMessageFormatter.formatMessage(Locale.getDefault(), 
 
329
                        "property-not-supported", new Object [] {identifier}));
 
330
            }
 
331
        }
 
332
    }
 
333
    
 
334
    public void setFeature(String name, boolean value)
 
335
        throws SAXNotRecognizedException, SAXNotSupportedException {
 
336
        if (name == null) {
 
337
            throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(), 
 
338
                    "FeatureNameNull", null));
 
339
        }
 
340
        if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
 
341
            fSecurityManager = value ? new SecurityManager() : null;
 
342
            fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager);
 
343
            return;
 
344
        }
 
345
        else if (name.equals(USE_GRAMMAR_POOL_ONLY)) {
 
346
            fUseGrammarPoolOnly = value;
 
347
            return;
 
348
        }
 
349
        try {
 
350
            fXMLSchemaLoader.setFeature(name, value);
 
351
        }
 
352
        catch (XMLConfigurationException e) {
 
353
            String identifier = e.getIdentifier();
 
354
            if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
 
355
                throw new SAXNotRecognizedException(
 
356
                        SAXMessageFormatter.formatMessage(Locale.getDefault(), 
 
357
                        "feature-not-recognized", new Object [] {identifier}));
 
358
            }
 
359
            else {
 
360
                throw new SAXNotSupportedException(
 
361
                        SAXMessageFormatter.formatMessage(Locale.getDefault(), 
 
362
                        "feature-not-supported", new Object [] {identifier}));
 
363
            }
 
364
        }
 
365
    }
 
366
    
 
367
    public void setProperty(String name, Object object)
 
368
        throws SAXNotRecognizedException, SAXNotSupportedException {
 
369
        if (name == null) {
 
370
            throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(), 
 
371
                    "ProperyNameNull", null));
 
372
        }
 
373
        if (name.equals(SECURITY_MANAGER)) {
 
374
            fSecurityManager = (SecurityManager) object;
 
375
            fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager);
 
376
            return;
 
377
        }
 
378
        else if (name.equals(XMLGRAMMAR_POOL)) {
 
379
            throw new SAXNotSupportedException(
 
380
                    SAXMessageFormatter.formatMessage(Locale.getDefault(), 
 
381
                    "property-not-supported", new Object [] {name}));
 
382
        }
 
383
        try {
 
384
            fXMLSchemaLoader.setProperty(name, object);
 
385
        }
 
386
        catch (XMLConfigurationException e) {
 
387
            String identifier = e.getIdentifier();
 
388
            if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
 
389
                throw new SAXNotRecognizedException(
 
390
                        SAXMessageFormatter.formatMessage(Locale.getDefault(), 
 
391
                        "property-not-recognized", new Object [] {identifier}));
 
392
            }
 
393
            else {
 
394
                throw new SAXNotSupportedException(
 
395
                        SAXMessageFormatter.formatMessage(Locale.getDefault(), 
 
396
                        "property-not-supported", new Object [] {identifier}));
 
397
            }
 
398
        }
 
399
    }
 
400
    
 
401
    private void propagateFeatures(AbstractXMLSchema schema) {
 
402
        schema.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, fSecurityManager != null);
 
403
        String[] features = fXMLSchemaLoader.getRecognizedFeatures();
 
404
        for (int i = 0; i < features.length; ++i) {
 
405
            boolean state = fXMLSchemaLoader.getFeature(features[i]);
 
406
            schema.setFeature(features[i], state);
 
407
        }
 
408
    }
 
409
    
 
410
    /** 
 
411
     * Extension of XMLGrammarPoolImpl which exposes the number of
 
412
     * grammars stored in the grammar pool.
 
413
     */
 
414
    static class XMLGrammarPoolImplExtension extends XMLGrammarPoolImpl {
 
415
        
 
416
        /** Constructs a grammar pool with a default number of buckets. */
 
417
        public XMLGrammarPoolImplExtension() {
 
418
            super();
 
419
        }
 
420
 
 
421
        /** Constructs a grammar pool with a specified number of buckets. */
 
422
        public XMLGrammarPoolImplExtension(int initialCapacity) {
 
423
            super(initialCapacity);
 
424
        }
 
425
        
 
426
        /** Returns the number of grammars contained in this pool. */
 
427
        int getGrammarCount() {
 
428
            return fGrammarCount;
 
429
        }
 
430
        
 
431
    } // XMLSchemaFactory.XMLGrammarPoolImplExtension
 
432
    
 
433
    /**
 
434
     * A grammar pool which wraps another.
 
435
     */
 
436
    static class XMLGrammarPoolWrapper implements XMLGrammarPool {
 
437
 
 
438
        private XMLGrammarPool fGrammarPool;
 
439
        
 
440
        /*
 
441
         * XMLGrammarPool methods
 
442
         */
 
443
        
 
444
        public Grammar[] retrieveInitialGrammarSet(String grammarType) {
 
445
            return fGrammarPool.retrieveInitialGrammarSet(grammarType);
 
446
        }
 
447
 
 
448
        public void cacheGrammars(String grammarType, Grammar[] grammars) {
 
449
            fGrammarPool.cacheGrammars(grammarType, grammars);
 
450
        }
 
451
 
 
452
        public Grammar retrieveGrammar(XMLGrammarDescription desc) {
 
453
            return fGrammarPool.retrieveGrammar(desc);
 
454
        }
 
455
 
 
456
        public void lockPool() {
 
457
            fGrammarPool.lockPool();
 
458
        }
 
459
 
 
460
        public void unlockPool() {
 
461
            fGrammarPool.unlockPool();
 
462
        }
 
463
 
 
464
        public void clear() {
 
465
            fGrammarPool.clear();
 
466
        }
 
467
        
 
468
        /*
 
469
         * Other methods
 
470
         */
 
471
        
 
472
        void setGrammarPool(XMLGrammarPool grammarPool) {
 
473
            fGrammarPool = grammarPool;
 
474
        }
 
475
        
 
476
        XMLGrammarPool getGrammarPool() {
 
477
            return fGrammarPool;
 
478
        }
 
479
        
 
480
    } // XMLSchemaFactory.XMLGrammarPoolWrapper
 
481
    
 
482
} // XMLSchemaFactory