001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.jaxp;
019:
020: import java.io.IOException;
021: import java.util.Enumeration;
022: import java.util.Hashtable;
023:
024: import javax.xml.parsers.DocumentBuilder;
025: import javax.xml.validation.Schema;
026:
027: import org.apache.xerces.dom.DOMImplementationImpl;
028: import org.apache.xerces.dom.DOMMessageFormatter;
029: import org.apache.xerces.impl.Constants;
030: import org.apache.xerces.impl.validation.ValidationManager;
031: import org.apache.xerces.impl.xs.XMLSchemaValidator;
032: import org.apache.xerces.jaxp.validation.XSGrammarPoolContainer;
033: import org.apache.xerces.parsers.DOMParser;
034: import org.apache.xerces.util.SecurityManager;
035: import org.apache.xerces.xni.XMLDocumentHandler;
036: import org.apache.xerces.xni.parser.XMLComponent;
037: import org.apache.xerces.xni.parser.XMLComponentManager;
038: import org.apache.xerces.xni.parser.XMLConfigurationException;
039: import org.apache.xerces.xni.parser.XMLDocumentSource;
040: import org.apache.xerces.xni.parser.XMLParserConfiguration;
041: import org.w3c.dom.DOMImplementation;
042: import org.w3c.dom.Document;
043: import org.xml.sax.EntityResolver;
044: import org.xml.sax.ErrorHandler;
045: import org.xml.sax.InputSource;
046: import org.xml.sax.SAXException;
047: import org.xml.sax.SAXNotRecognizedException;
048: import org.xml.sax.SAXNotSupportedException;
049:
050: /**
051: * @author Rajiv Mordani
052: * @author Edwin Goei
053: * @version $Id: DocumentBuilderImpl.java 520058 2007-03-19 19:33:53Z mrglavas $
054: */
055: public class DocumentBuilderImpl extends DocumentBuilder implements
056: JAXPConstants {
057: /** Feature identifier: namespaces. */
058: private static final String NAMESPACES_FEATURE = Constants.SAX_FEATURE_PREFIX
059: + Constants.NAMESPACES_FEATURE;
060:
061: /** Feature identifier: include ignorable white space. */
062: private static final String INCLUDE_IGNORABLE_WHITESPACE = Constants.XERCES_FEATURE_PREFIX
063: + Constants.INCLUDE_IGNORABLE_WHITESPACE;
064:
065: /** Feature identifier: create entiry ref nodes feature. */
066: private static final String CREATE_ENTITY_REF_NODES_FEATURE = Constants.XERCES_FEATURE_PREFIX
067: + Constants.CREATE_ENTITY_REF_NODES_FEATURE;
068:
069: /** Feature identifier: include comments feature. */
070: private static final String INCLUDE_COMMENTS_FEATURE = Constants.XERCES_FEATURE_PREFIX
071: + Constants.INCLUDE_COMMENTS_FEATURE;
072:
073: /** Feature identifier: create cdata nodes feature. */
074: private static final String CREATE_CDATA_NODES_FEATURE = Constants.XERCES_FEATURE_PREFIX
075: + Constants.CREATE_CDATA_NODES_FEATURE;
076:
077: /** Feature identifier: XInclude processing */
078: private static final String XINCLUDE_FEATURE = Constants.XERCES_FEATURE_PREFIX
079: + Constants.XINCLUDE_FEATURE;
080:
081: /** feature identifier: XML Schema validation */
082: private static final String XMLSCHEMA_VALIDATION_FEATURE = Constants.XERCES_FEATURE_PREFIX
083: + Constants.SCHEMA_VALIDATION_FEATURE;
084:
085: /** Feature identifier: validation */
086: private static final String VALIDATION_FEATURE = Constants.SAX_FEATURE_PREFIX
087: + Constants.VALIDATION_FEATURE;
088:
089: /** Property identifier: security manager. */
090: private static final String SECURITY_MANAGER = Constants.XERCES_PROPERTY_PREFIX
091: + Constants.SECURITY_MANAGER_PROPERTY;
092:
093: private DOMParser domParser = null;
094: private final Schema grammar;
095:
096: private XMLComponent fSchemaValidator;
097: private XMLComponentManager fSchemaValidatorComponentManager;
098: private ValidationManager fSchemaValidationManager;
099: private UnparsedEntityHandler fUnparsedEntityHandler;
100:
101: /** Initial ErrorHandler */
102: private final ErrorHandler fInitErrorHandler;
103:
104: /** Initial EntityResolver */
105: private final EntityResolver fInitEntityResolver;
106:
107: DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf,
108: Hashtable dbfAttrs, Hashtable features)
109: throws SAXNotRecognizedException, SAXNotSupportedException {
110: this (dbf, dbfAttrs, features, false);
111: }
112:
113: DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf,
114: Hashtable dbfAttrs, Hashtable features,
115: boolean secureProcessing) throws SAXNotRecognizedException,
116: SAXNotSupportedException {
117: domParser = new DOMParser();
118:
119: // If validating, provide a default ErrorHandler that prints
120: // validation errors with a warning telling the user to set an
121: // ErrorHandler
122: if (dbf.isValidating()) {
123: fInitErrorHandler = new DefaultValidationErrorHandler();
124: setErrorHandler(fInitErrorHandler);
125: } else {
126: fInitErrorHandler = domParser.getErrorHandler();
127: }
128:
129: domParser.setFeature(VALIDATION_FEATURE, dbf.isValidating());
130:
131: // "namespaceAware" == SAX Namespaces feature
132: domParser
133: .setFeature(NAMESPACES_FEATURE, dbf.isNamespaceAware());
134:
135: // Set various parameters obtained from DocumentBuilderFactory
136: domParser.setFeature(INCLUDE_IGNORABLE_WHITESPACE, !dbf
137: .isIgnoringElementContentWhitespace());
138: domParser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, !dbf
139: .isExpandEntityReferences());
140: domParser.setFeature(INCLUDE_COMMENTS_FEATURE, !dbf
141: .isIgnoringComments());
142: domParser.setFeature(CREATE_CDATA_NODES_FEATURE, !dbf
143: .isCoalescing());
144:
145: // Avoid setting the XInclude processing feature if the value is false.
146: // This will keep the configuration from throwing an exception if it
147: // does not support XInclude.
148: if (dbf.isXIncludeAware()) {
149: domParser.setFeature(XINCLUDE_FEATURE, true);
150: }
151:
152: // If the secure processing feature is on set a security manager.
153: if (secureProcessing) {
154: domParser.setProperty(SECURITY_MANAGER,
155: new SecurityManager());
156: }
157:
158: this .grammar = dbf.getSchema();
159: if (grammar != null) {
160: XMLParserConfiguration config = domParser
161: .getXMLParserConfiguration();
162: XMLComponent validatorComponent = null;
163: /** For Xerces grammars, use built-in schema validator. **/
164: if (grammar instanceof XSGrammarPoolContainer) {
165: validatorComponent = new XMLSchemaValidator();
166: fSchemaValidationManager = new ValidationManager();
167: fUnparsedEntityHandler = new UnparsedEntityHandler(
168: fSchemaValidationManager);
169: config.setDTDHandler(fUnparsedEntityHandler);
170: fUnparsedEntityHandler.setDTDHandler(domParser);
171: domParser.setDTDSource(fUnparsedEntityHandler);
172: fSchemaValidatorComponentManager = new SchemaValidatorConfiguration(
173: config, (XSGrammarPoolContainer) grammar,
174: fSchemaValidationManager);
175: }
176: /** For third party grammars, use the JAXP validator component. **/
177: else {
178: validatorComponent = new JAXPValidatorComponent(grammar
179: .newValidatorHandler());
180: fSchemaValidatorComponentManager = config;
181: }
182: config.addRecognizedFeatures(validatorComponent
183: .getRecognizedFeatures());
184: config.addRecognizedProperties(validatorComponent
185: .getRecognizedProperties());
186: config
187: .setDocumentHandler((XMLDocumentHandler) validatorComponent);
188: ((XMLDocumentSource) validatorComponent)
189: .setDocumentHandler(domParser);
190: domParser
191: .setDocumentSource((XMLDocumentSource) validatorComponent);
192: fSchemaValidator = validatorComponent;
193: }
194:
195: // Set features
196: setFeatures(features);
197:
198: // Set attributes
199: setDocumentBuilderFactoryAttributes(dbfAttrs);
200:
201: // Initial EntityResolver
202: fInitEntityResolver = domParser.getEntityResolver();
203: }
204:
205: private void setFeatures(Hashtable features)
206: throws SAXNotSupportedException, SAXNotRecognizedException {
207: if (features != null) {
208: for (Enumeration e = features.keys(); e.hasMoreElements();) {
209: String feature = (String) e.nextElement();
210: boolean value = ((Boolean) features.get(feature))
211: .booleanValue();
212: domParser.setFeature(feature, value);
213: }
214: }
215: }
216:
217: /**
218: * Set any DocumentBuilderFactory attributes of our underlying DOMParser
219: *
220: * Note: code does not handle possible conflicts between DOMParser
221: * attribute names and JAXP specific attribute names,
222: * eg. DocumentBuilderFactory.setValidating()
223: */
224: private void setDocumentBuilderFactoryAttributes(Hashtable dbfAttrs)
225: throws SAXNotSupportedException, SAXNotRecognizedException {
226: if (dbfAttrs == null) {
227: // Nothing to do
228: return;
229: }
230:
231: for (Enumeration e = dbfAttrs.keys(); e.hasMoreElements();) {
232: String name = (String) e.nextElement();
233: Object val = dbfAttrs.get(name);
234: if (val instanceof Boolean) {
235: // Assume feature
236: domParser.setFeature(name, ((Boolean) val)
237: .booleanValue());
238: } else {
239: // Assume property
240: if (JAXP_SCHEMA_LANGUAGE.equals(name)) {
241: // JAXP 1.2 support
242: //None of the properties will take effect till the setValidating(true) has been called
243: if (W3C_XML_SCHEMA.equals(val)) {
244: if (isValidating()) {
245: domParser.setFeature(
246: XMLSCHEMA_VALIDATION_FEATURE, true);
247: // this should allow us not to emit DTD errors, as expected by the
248: // spec when schema validation is enabled
249: domParser.setProperty(JAXP_SCHEMA_LANGUAGE,
250: W3C_XML_SCHEMA);
251: }
252: }
253: } else if (JAXP_SCHEMA_SOURCE.equals(name)) {
254: if (isValidating()) {
255: String value = (String) dbfAttrs
256: .get(JAXP_SCHEMA_LANGUAGE);
257: if (value != null
258: && W3C_XML_SCHEMA.equals(value)) {
259: domParser.setProperty(name, val);
260: } else {
261: throw new IllegalArgumentException(
262: DOMMessageFormatter
263: .formatMessage(
264: DOMMessageFormatter.DOM_DOMAIN,
265: "jaxp-order-not-supported",
266: new Object[] {
267: JAXP_SCHEMA_LANGUAGE,
268: JAXP_SCHEMA_SOURCE }));
269: }
270: }
271: } else {
272: // Let Xerces code handle the property
273: domParser.setProperty(name, val);
274: }
275: }
276: }
277: }
278:
279: /**
280: * Non-preferred: use the getDOMImplementation() method instead of this
281: * one to get a DOM Level 2 DOMImplementation object and then use DOM
282: * Level 2 methods to create a DOM Document object.
283: */
284: public Document newDocument() {
285: return new org.apache.xerces.dom.DocumentImpl();
286: }
287:
288: public DOMImplementation getDOMImplementation() {
289: return DOMImplementationImpl.getDOMImplementation();
290: }
291:
292: public Document parse(InputSource is) throws SAXException,
293: IOException {
294: if (is == null) {
295: throw new IllegalArgumentException(DOMMessageFormatter
296: .formatMessage(DOMMessageFormatter.DOM_DOMAIN,
297: "jaxp-null-input-source", null));
298: }
299: if (fSchemaValidator != null) {
300: if (fSchemaValidationManager != null) {
301: fSchemaValidationManager.reset();
302: fUnparsedEntityHandler.reset();
303: }
304: resetSchemaValidator();
305: }
306: domParser.parse(is);
307: Document doc = domParser.getDocument();
308: domParser.dropDocumentReferences();
309: return doc;
310: }
311:
312: public boolean isNamespaceAware() {
313: try {
314: return domParser.getFeature(NAMESPACES_FEATURE);
315: } catch (SAXException x) {
316: throw new IllegalStateException(x.getMessage());
317: }
318: }
319:
320: public boolean isValidating() {
321: try {
322: return domParser.getFeature(VALIDATION_FEATURE);
323: } catch (SAXException x) {
324: throw new IllegalStateException(x.getMessage());
325: }
326: }
327:
328: /**
329: * Gets the XInclude processing mode for this parser
330: * @return the state of XInclude processing mode
331: */
332: public boolean isXIncludeAware() {
333: try {
334: return domParser.getFeature(XINCLUDE_FEATURE);
335: } catch (SAXException exc) {
336: return false;
337: }
338: }
339:
340: public void setEntityResolver(EntityResolver er) {
341: domParser.setEntityResolver(er);
342: }
343:
344: public void setErrorHandler(ErrorHandler eh) {
345: domParser.setErrorHandler(eh);
346: }
347:
348: public Schema getSchema() {
349: return grammar;
350: }
351:
352: public void reset() {
353: /** Restore the initial error handler. **/
354: if (domParser.getErrorHandler() != fInitErrorHandler) {
355: domParser.setErrorHandler(fInitErrorHandler);
356: }
357: /** Restore the initial entity resolver. **/
358: if (domParser.getEntityResolver() != fInitEntityResolver) {
359: domParser.setEntityResolver(fInitEntityResolver);
360: }
361: }
362:
363: // package private
364: DOMParser getDOMParser() {
365: return domParser;
366: }
367:
368: private void resetSchemaValidator() throws SAXException {
369: try {
370: fSchemaValidator.reset(fSchemaValidatorComponentManager);
371: }
372: // This should never be thrown from the schema validator.
373: catch (XMLConfigurationException e) {
374: throw new SAXException(e);
375: }
376: }
377: }
|