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
9
* http://www.apache.org/licenses/LICENSE-2.0
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.
18
package org.apache.xerces.jaxp.validation;
20
import java.io.IOException;
21
import java.io.InputStream;
22
import java.io.Reader;
23
import java.util.Locale;
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;
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;
58
* {@link SchemaFactory} for XML Schema.
60
* @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
61
* @version $Id: XMLSchemaFactory.java,v 1.2 2009/12/10 03:18:25 matthewoliver Exp $
63
public final class XMLSchemaFactory extends SchemaFactory {
65
// feature identifiers
67
/** Feature identifier: schema full checking. */
68
private static final String SCHEMA_FULL_CHECKING =
69
Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING;
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;
75
// property identifiers
77
/** Property identifier: grammar pool. */
78
private static final String XMLGRAMMAR_POOL =
79
Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
81
/** Property identifier: SecurityManager. */
82
private static final String SECURITY_MANAGER =
83
Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
89
/** The XMLSchemaLoader */
90
private final XMLSchemaLoader fXMLSchemaLoader = new XMLSchemaLoader();
92
/** User-specified ErrorHandler; can be null. */
93
private ErrorHandler fErrorHandler;
95
/** The LSResrouceResolver */
96
private LSResourceResolver fLSResourceResolver;
98
/** The DOMEntityResolverWrapper */
99
private final DOMEntityResolverWrapper fDOMEntityResolverWrapper;
101
/** The ErrorHandlerWrapper */
102
private final ErrorHandlerWrapper fErrorHandlerWrapper;
104
/** The SecurityManager. */
105
private SecurityManager fSecurityManager;
107
/** The container for the real grammar pool. */
108
private final XMLGrammarPoolWrapper fXMLGrammarPoolWrapper;
110
/** Whether or not to allow new schemas to be added to the grammar pool */
111
private boolean fUseGrammarPoolOnly;
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;
125
* <p>Is specified schema supported by this <code>SchemaFactory</code>?</p>
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.
130
* @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>.
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.
136
public boolean isSchemaLanguageSupported(String schemaLanguage) {
137
if (schemaLanguage == null) {
138
throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(),
139
"SchemaLanguageNull", null));
141
if (schemaLanguage.length() == 0) {
142
throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(),
143
"SchemaLanguageLengthZero", null));
145
// only W3C XML Schema 1.0 is supported
146
return schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI);
149
public LSResourceResolver getResourceResolver() {
150
return fLSResourceResolver;
153
public void setResourceResolver(LSResourceResolver resourceResolver) {
154
fLSResourceResolver = resourceResolver;
155
fDOMEntityResolverWrapper.setEntityResolver(resourceResolver);
156
fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper);
159
public ErrorHandler getErrorHandler() {
160
return fErrorHandler;
163
public void setErrorHandler(ErrorHandler errorHandler) {
164
fErrorHandler = errorHandler;
165
fErrorHandlerWrapper.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance());
166
fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper);
169
public Schema newSchema( Source[] schemas ) throws SAXException {
171
// this will let the loader store parsed Grammars into the pool.
172
XMLGrammarPoolImplExtension pool = new XMLGrammarPoolImplExtension();
173
fXMLGrammarPoolWrapper.setGrammarPool(pool);
175
XMLInputSource[] xmlInputSources = new XMLInputSource[schemas.length];
176
InputStream inputStream;
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);
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));
197
xmlInputSources[i] = new SAXInputSource(saxSource.getXMLReader(), inputSource);
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);
205
else if (source == null) {
206
throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(),
207
"SchemaSourceArrayMemberNull", null));
210
throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(),
211
"SchemaFactorySourceUnrecognized",
212
new Object [] {source.getClass().getName()}));
217
fXMLSchemaLoader.loadGrammar(xmlInputSources);
219
catch (XNIException e) {
220
// this should have been reported to users already.
221
throw Util.toSAXException(e);
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);
229
throw se; // and we must throw it.
232
// Clear reference to grammar pool.
233
fXMLGrammarPoolWrapper.setGrammarPool(null);
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));
242
else if (grammarCount == 1) {
243
Grammar[] grammars = pool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA);
244
schema = new SimpleXMLSchema(grammars[0]);
247
schema = new EmptyXMLSchema();
251
schema = new XMLSchema(new ReadOnlyGrammarPool(pool), false);
253
propagateFeatures(schema);
257
public Schema newSchema() throws SAXException {
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
266
// Use a Schema that uses the system id as the equality source.
267
AbstractXMLSchema schema = new WeakReferenceXMLSchema();
268
propagateFeatures(schema);
272
public boolean getFeature(String name)
273
throws SAXNotRecognizedException, SAXNotSupportedException {
275
throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(),
276
"FeatureNameNull", null));
278
if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
279
return (fSecurityManager != null);
281
else if (name.equals(USE_GRAMMAR_POOL_ONLY)) {
282
return fUseGrammarPoolOnly;
285
return fXMLSchemaLoader.getFeature(name);
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}));
295
throw new SAXNotSupportedException(
296
SAXMessageFormatter.formatMessage(Locale.getDefault(),
297
"feature-not-supported", new Object [] {identifier}));
302
public Object getProperty(String name)
303
throws SAXNotRecognizedException, SAXNotSupportedException {
305
throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(),
306
"ProperyNameNull", null));
308
if (name.equals(SECURITY_MANAGER)) {
309
return fSecurityManager;
311
else if (name.equals(XMLGRAMMAR_POOL)) {
312
throw new SAXNotSupportedException(
313
SAXMessageFormatter.formatMessage(Locale.getDefault(),
314
"property-not-supported", new Object [] {name}));
317
return fXMLSchemaLoader.getProperty(name);
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}));
327
throw new SAXNotSupportedException(
328
SAXMessageFormatter.formatMessage(Locale.getDefault(),
329
"property-not-supported", new Object [] {identifier}));
334
public void setFeature(String name, boolean value)
335
throws SAXNotRecognizedException, SAXNotSupportedException {
337
throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(),
338
"FeatureNameNull", null));
340
if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
341
fSecurityManager = value ? new SecurityManager() : null;
342
fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager);
345
else if (name.equals(USE_GRAMMAR_POOL_ONLY)) {
346
fUseGrammarPoolOnly = value;
350
fXMLSchemaLoader.setFeature(name, value);
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}));
360
throw new SAXNotSupportedException(
361
SAXMessageFormatter.formatMessage(Locale.getDefault(),
362
"feature-not-supported", new Object [] {identifier}));
367
public void setProperty(String name, Object object)
368
throws SAXNotRecognizedException, SAXNotSupportedException {
370
throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(Locale.getDefault(),
371
"ProperyNameNull", null));
373
if (name.equals(SECURITY_MANAGER)) {
374
fSecurityManager = (SecurityManager) object;
375
fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager);
378
else if (name.equals(XMLGRAMMAR_POOL)) {
379
throw new SAXNotSupportedException(
380
SAXMessageFormatter.formatMessage(Locale.getDefault(),
381
"property-not-supported", new Object [] {name}));
384
fXMLSchemaLoader.setProperty(name, object);
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}));
394
throw new SAXNotSupportedException(
395
SAXMessageFormatter.formatMessage(Locale.getDefault(),
396
"property-not-supported", new Object [] {identifier}));
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);
411
* Extension of XMLGrammarPoolImpl which exposes the number of
412
* grammars stored in the grammar pool.
414
static class XMLGrammarPoolImplExtension extends XMLGrammarPoolImpl {
416
/** Constructs a grammar pool with a default number of buckets. */
417
public XMLGrammarPoolImplExtension() {
421
/** Constructs a grammar pool with a specified number of buckets. */
422
public XMLGrammarPoolImplExtension(int initialCapacity) {
423
super(initialCapacity);
426
/** Returns the number of grammars contained in this pool. */
427
int getGrammarCount() {
428
return fGrammarCount;
431
} // XMLSchemaFactory.XMLGrammarPoolImplExtension
434
* A grammar pool which wraps another.
436
static class XMLGrammarPoolWrapper implements XMLGrammarPool {
438
private XMLGrammarPool fGrammarPool;
441
* XMLGrammarPool methods
444
public Grammar[] retrieveInitialGrammarSet(String grammarType) {
445
return fGrammarPool.retrieveInitialGrammarSet(grammarType);
448
public void cacheGrammars(String grammarType, Grammar[] grammars) {
449
fGrammarPool.cacheGrammars(grammarType, grammars);
452
public Grammar retrieveGrammar(XMLGrammarDescription desc) {
453
return fGrammarPool.retrieveGrammar(desc);
456
public void lockPool() {
457
fGrammarPool.lockPool();
460
public void unlockPool() {
461
fGrammarPool.unlockPool();
464
public void clear() {
465
fGrammarPool.clear();
472
void setGrammarPool(XMLGrammarPool grammarPool) {
473
fGrammarPool = grammarPool;
476
XMLGrammarPool getGrammarPool() {
480
} // XMLSchemaFactory.XMLGrammarPoolWrapper
482
} // XMLSchemaFactory