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;
19
20 import java.io.IOException;
21 import java.util.Enumeration;
22 import java.util.Hashtable;
23
24 import javax.xml.parsers.DocumentBuilder;
25 import javax.xml.validation.Schema;
26
27 import org.apache.xerces.dom.DOMImplementationImpl;
28 import org.apache.xerces.dom.DOMMessageFormatter;
29 import org.apache.xerces.impl.Constants;
30 import org.apache.xerces.impl.validation.ValidationManager;
31 import org.apache.xerces.impl.xs.XMLSchemaValidator;
32 import org.apache.xerces.jaxp.validation.XSGrammarPoolContainer;
33 import org.apache.xerces.parsers.DOMParser;
34 import org.apache.xerces.util.SecurityManager;
35 import org.apache.xerces.xni.XMLDocumentHandler;
36 import org.apache.xerces.xni.parser.XMLComponent;
37 import org.apache.xerces.xni.parser.XMLComponentManager;
38 import org.apache.xerces.xni.parser.XMLConfigurationException;
39 import org.apache.xerces.xni.parser.XMLDocumentSource;
40 import org.apache.xerces.xni.parser.XMLParserConfiguration;
41 import org.w3c.dom.DOMImplementation;
42 import org.w3c.dom.Document;
43 import org.xml.sax.EntityResolver;
44 import org.xml.sax.ErrorHandler;
45 import org.xml.sax.InputSource;
46 import org.xml.sax.SAXException;
47 import org.xml.sax.SAXNotRecognizedException;
48 import org.xml.sax.SAXNotSupportedException;
49
50 /**
51 * @author Rajiv Mordani
52 * @author Edwin Goei
53 * @version $Id: DocumentBuilderImpl.java 520058 2007-03-19 19:33:53Z mrglavas $
54 */
55 public class DocumentBuilderImpl extends DocumentBuilder
56 implements JAXPConstants
57 {
58 /** Feature identifier: namespaces. */
59 private static final String NAMESPACES_FEATURE =
60 Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
61
62 /** Feature identifier: include ignorable white space. */
63 private static final String INCLUDE_IGNORABLE_WHITESPACE =
64 Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE;
65
66 /** Feature identifier: create entiry ref nodes feature. */
67 private static final String CREATE_ENTITY_REF_NODES_FEATURE =
68 Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE;
69
70 /** Feature identifier: include comments feature. */
71 private static final String INCLUDE_COMMENTS_FEATURE =
72 Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE;
73
74 /** Feature identifier: create cdata nodes feature. */
75 private static final String CREATE_CDATA_NODES_FEATURE =
76 Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE;
77
78 /** Feature identifier: XInclude processing */
79 private static final String XINCLUDE_FEATURE =
80 Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FEATURE;
81
82 /** feature identifier: XML Schema validation */
83 private static final String XMLSCHEMA_VALIDATION_FEATURE =
84 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
85
86 /** Feature identifier: validation */
87 private static final String VALIDATION_FEATURE =
88 Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
89
90 /** Property identifier: security manager. */
91 private static final String SECURITY_MANAGER =
92 Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
93
94 private DOMParser domParser = null;
95 private final Schema grammar;
96
97 private XMLComponent fSchemaValidator;
98 private XMLComponentManager fSchemaValidatorComponentManager;
99 private ValidationManager fSchemaValidationManager;
100 private UnparsedEntityHandler fUnparsedEntityHandler;
101
102 /** Initial ErrorHandler */
103 private final ErrorHandler fInitErrorHandler;
104
105 /** Initial EntityResolver */
106 private final EntityResolver fInitEntityResolver;
107
108 DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Hashtable dbfAttrs, Hashtable features)
109 throws SAXNotRecognizedException, SAXNotSupportedException {
110 this(dbf, dbfAttrs, features, false);
111 }
112
113 DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Hashtable dbfAttrs, Hashtable features, boolean secureProcessing)
114 throws SAXNotRecognizedException, SAXNotSupportedException
115 {
116 domParser = new DOMParser();
117
118 // If validating, provide a default ErrorHandler that prints
119 // validation errors with a warning telling the user to set an
120 // ErrorHandler
121 if (dbf.isValidating()) {
122 fInitErrorHandler = new DefaultValidationErrorHandler();
123 setErrorHandler(fInitErrorHandler);
124 }
125 else {
126 fInitErrorHandler = domParser.getErrorHandler();
127 }
128
129 domParser.setFeature(VALIDATION_FEATURE, dbf.isValidating());
130
131 // "namespaceAware" == SAX Namespaces feature
132 domParser.setFeature(NAMESPACES_FEATURE, dbf.isNamespaceAware());
133
134 // Set various parameters obtained from DocumentBuilderFactory
135 domParser.setFeature(INCLUDE_IGNORABLE_WHITESPACE,
136 !dbf.isIgnoringElementContentWhitespace());
137 domParser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE,
138 !dbf.isExpandEntityReferences());
139 domParser.setFeature(INCLUDE_COMMENTS_FEATURE,
140 !dbf.isIgnoringComments());
141 domParser.setFeature(CREATE_CDATA_NODES_FEATURE,
142 !dbf.isCoalescing());
143
144 // Avoid setting the XInclude processing feature if the value is false.
145 // This will keep the configuration from throwing an exception if it
146 // does not support XInclude.
147 if (dbf.isXIncludeAware()) {
148 domParser.setFeature(XINCLUDE_FEATURE, true);
149 }
150
151 // If the secure processing feature is on set a security manager.
152 if (secureProcessing) {
153 domParser.setProperty(SECURITY_MANAGER, new SecurityManager());
154 }
155
156 this.grammar = dbf.getSchema();
157 if (grammar != null) {
158 XMLParserConfiguration config = domParser.getXMLParserConfiguration();
159 XMLComponent validatorComponent = null;
160 /** For Xerces grammars, use built-in schema validator. **/
161 if (grammar instanceof XSGrammarPoolContainer) {
162 validatorComponent = new XMLSchemaValidator();
163 fSchemaValidationManager = new ValidationManager();
164 fUnparsedEntityHandler = new UnparsedEntityHandler(fSchemaValidationManager);
165 config.setDTDHandler(fUnparsedEntityHandler);
166 fUnparsedEntityHandler.setDTDHandler(domParser);
167 domParser.setDTDSource(fUnparsedEntityHandler);
168 fSchemaValidatorComponentManager = new SchemaValidatorConfiguration(config,
169 (XSGrammarPoolContainer) grammar, fSchemaValidationManager);
170 }
171 /** For third party grammars, use the JAXP validator component. **/
172 else {
173 validatorComponent = new JAXPValidatorComponent(grammar.newValidatorHandler());
174 fSchemaValidatorComponentManager = config;
175 }
176 config.addRecognizedFeatures(validatorComponent.getRecognizedFeatures());
177 config.addRecognizedProperties(validatorComponent.getRecognizedProperties());
178 config.setDocumentHandler((XMLDocumentHandler) validatorComponent);
179 ((XMLDocumentSource)validatorComponent).setDocumentHandler(domParser);
180 domParser.setDocumentSource((XMLDocumentSource) validatorComponent);
181 fSchemaValidator = validatorComponent;
182 }
183
184 // Set features
185 setFeatures(features);
186
187 // Set attributes
188 setDocumentBuilderFactoryAttributes(dbfAttrs);
189
190 // Initial EntityResolver
191 fInitEntityResolver = domParser.getEntityResolver();
192 }
193
194 private void setFeatures(Hashtable features)
195 throws SAXNotSupportedException, SAXNotRecognizedException {
196 if (features != null) {
197 for (Enumeration e = features.keys(); e.hasMoreElements();) {
198 String feature = (String)e.nextElement();
199 boolean value = ((Boolean)features.get(feature)).booleanValue();
200 domParser.setFeature(feature, value);
201 }
202 }
203 }
204
205 /**
206 * Set any DocumentBuilderFactory attributes of our underlying DOMParser
207 *
208 * Note: code does not handle possible conflicts between DOMParser
209 * attribute names and JAXP specific attribute names,
210 * eg. DocumentBuilderFactory.setValidating()
211 */
212 private void setDocumentBuilderFactoryAttributes(Hashtable dbfAttrs)
213 throws SAXNotSupportedException, SAXNotRecognizedException
214 {
215 if (dbfAttrs == null) {
216 // Nothing to do
217 return;
218 }
219
220 for (Enumeration e = dbfAttrs.keys(); e.hasMoreElements();) {
221 String name = (String)e.nextElement();
222 Object val = dbfAttrs.get(name);
223 if (val instanceof Boolean) {
224 // Assume feature
225 domParser.setFeature(name, ((Boolean)val).booleanValue());
226 } else {
227 // Assume property
228 if (JAXP_SCHEMA_LANGUAGE.equals(name)) {
229 // JAXP 1.2 support
230 //None of the properties will take effect till the setValidating(true) has been called
231 if ( W3C_XML_SCHEMA.equals(val) ) {
232 if( isValidating() ) {
233 domParser.setFeature(XMLSCHEMA_VALIDATION_FEATURE, true);
234 // this should allow us not to emit DTD errors, as expected by the
235 // spec when schema validation is enabled
236 domParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
237 }
238 }
239 } else if(JAXP_SCHEMA_SOURCE.equals(name)){
240 if( isValidating() ) {
241 String value=(String)dbfAttrs.get(JAXP_SCHEMA_LANGUAGE);
242 if(value !=null && W3C_XML_SCHEMA.equals(value)){
243 domParser.setProperty(name, val);
244 }else{
245 throw new IllegalArgumentException(
246 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
247 "jaxp-order-not-supported",
248 new Object[] {JAXP_SCHEMA_LANGUAGE, JAXP_SCHEMA_SOURCE}));
249 }
250 }
251 } else {
252 // Let Xerces code handle the property
253 domParser.setProperty(name, val);
254 }
255 }
256 }
257 }
258
259 /**
260 * Non-preferred: use the getDOMImplementation() method instead of this
261 * one to get a DOM Level 2 DOMImplementation object and then use DOM
262 * Level 2 methods to create a DOM Document object.
263 */
264 public Document newDocument() {
265 return new org.apache.xerces.dom.DocumentImpl();
266 }
267
268 public DOMImplementation getDOMImplementation() {
269 return DOMImplementationImpl.getDOMImplementation();
270 }
271
272 public Document parse(InputSource is) throws SAXException, IOException {
273 if (is == null) {
274 throw new IllegalArgumentException(
275 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
276 "jaxp-null-input-source", null));
277 }
278 if (fSchemaValidator != null) {
279 if (fSchemaValidationManager != null) {
280 fSchemaValidationManager.reset();
281 fUnparsedEntityHandler.reset();
282 }
283 resetSchemaValidator();
284 }
285 domParser.parse(is);
286 Document doc = domParser.getDocument();
287 domParser.dropDocumentReferences();
288 return doc;
289 }
290
291 public boolean isNamespaceAware() {
292 try {
293 return domParser.getFeature(NAMESPACES_FEATURE);
294 }
295 catch (SAXException x) {
296 throw new IllegalStateException(x.getMessage());
297 }
298 }
299
300 public boolean isValidating() {
301 try {
302 return domParser.getFeature(VALIDATION_FEATURE);
303 }
304 catch (SAXException x) {
305 throw new IllegalStateException(x.getMessage());
306 }
307 }
308
309 /**
310 * Gets the XInclude processing mode for this parser
311 * @return the state of XInclude processing mode
312 */
313 public boolean isXIncludeAware() {
314 try {
315 return domParser.getFeature(XINCLUDE_FEATURE);
316 }
317 catch (SAXException exc) {
318 return false;
319 }
320 }
321
322 public void setEntityResolver(EntityResolver er) {
323 domParser.setEntityResolver(er);
324 }
325
326 public void setErrorHandler(ErrorHandler eh) {
327 domParser.setErrorHandler(eh);
328 }
329
330 public Schema getSchema() {
331 return grammar;
332 }
333
334 public void reset() {
335 /** Restore the initial error handler. **/
336 if (domParser.getErrorHandler() != fInitErrorHandler) {
337 domParser.setErrorHandler(fInitErrorHandler);
338 }
339 /** Restore the initial entity resolver. **/
340 if (domParser.getEntityResolver() != fInitEntityResolver) {
341 domParser.setEntityResolver(fInitEntityResolver);
342 }
343 }
344
345 // package private
346 DOMParser getDOMParser() {
347 return domParser;
348 }
349
350 private void resetSchemaValidator() throws SAXException {
351 try {
352 fSchemaValidator.reset(fSchemaValidatorComponentManager);
353 }
354 // This should never be thrown from the schema validator.
355 catch (XMLConfigurationException e) {
356 throw new SAXException(e);
357 }
358 }
359 }