View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2000-2005 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package com.sun.org.apache.xerces.internal.parsers;
22  
23  import java.io.IOException;
24  
25  import com.sun.org.apache.xerces.internal.impl.Constants;
26  import com.sun.org.apache.xerces.internal.util.EntityResolverWrapper;
27  import com.sun.org.apache.xerces.internal.util.EntityResolver2Wrapper;
28  import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper;
29  import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter;
30  import com.sun.org.apache.xerces.internal.util.Status;
31  import com.sun.org.apache.xerces.internal.util.SymbolTable;
32  import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
33  import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
34  import com.sun.org.apache.xerces.internal.xni.XNIException;
35  import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
36  import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
37  import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
38  import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
39  import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
40  import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
41  import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
42  import org.w3c.dom.Node;
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  import org.xml.sax.SAXParseException;
50  import org.xml.sax.ext.EntityResolver2;
51  import org.xml.sax.helpers.LocatorImpl;
52  
53  /**
54   * This is the main Xerces DOM parser class. It uses the abstract DOM
55   * parser with a document scanner, a dtd scanner, and a validator, as
56   * well as a grammar pool.
57   *
58   * @author Arnaud  Le Hors, IBM
59   * @author Andy Clark, IBM
60   *
61   * @version $Id: DOMParser.java,v 1.7 2010-11-01 04:40:09 joehw Exp $
62   */
63  public class DOMParser
64      extends AbstractDOMParser {
65  
66      //
67      // Constants
68      //
69  
70      // features
71  
72      /** Feature identifier: EntityResolver2. */
73      protected static final String USE_ENTITY_RESOLVER2 =
74          Constants.SAX_FEATURE_PREFIX + Constants.USE_ENTITY_RESOLVER2_FEATURE;
75  
76      protected static final String REPORT_WHITESPACE =
77              Constants.SUN_SCHEMA_FEATURE_PREFIX + Constants.SUN_REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE;
78  
79      /** Property identifier: Security property manager. */
80      private static final String XML_SECURITY_PROPERTY_MANAGER =
81              Constants.XML_SECURITY_PROPERTY_MANAGER;
82  
83      // recognized features:
84      private static final String[] RECOGNIZED_FEATURES = {
85          REPORT_WHITESPACE
86      };
87  
88      // properties
89  
90      /** Property identifier: symbol table. */
91      protected static final String SYMBOL_TABLE =
92          Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
93  
94      /** Property identifier: XML grammar pool. */
95      protected static final String XMLGRAMMAR_POOL =
96          Constants.XERCES_PROPERTY_PREFIX+Constants.XMLGRAMMAR_POOL_PROPERTY;
97  
98      /** Recognized properties. */
99      private static final String[] RECOGNIZED_PROPERTIES = {
100         SYMBOL_TABLE,
101         XMLGRAMMAR_POOL,
102     };
103 
104     //
105     // Data
106     //
107 
108     // features
109 
110     /** Use EntityResolver2. */
111     protected boolean fUseEntityResolver2 = true;
112 
113     //
114     // Constructors
115     //
116 
117     /**
118      * Constructs a DOM parser using the specified parser configuration.
119      */
120     public DOMParser(XMLParserConfiguration config) {
121         super(config);
122     } // <init>(XMLParserConfiguration)
123 
124     /**
125      * Constructs a DOM parser using the dtd/xml schema parser configuration.
126      */
127     public DOMParser() {
128         this(null, null);
129     } // <init>()
130 
131     /**
132      * Constructs a DOM parser using the specified symbol table.
133      */
134     public DOMParser(SymbolTable symbolTable) {
135         this(symbolTable, null);
136     } // <init>(SymbolTable)
137 
138 
139     /**
140      * Constructs a DOM parser using the specified symbol table and
141      * grammar pool.
142      */
143     public DOMParser(SymbolTable symbolTable, XMLGrammarPool grammarPool) {
144         super(new XIncludeAwareParserConfiguration());
145 
146         // set properties
147         fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES);
148         if (symbolTable != null) {
149             fConfiguration.setProperty(SYMBOL_TABLE, symbolTable);
150         }
151         if (grammarPool != null) {
152             fConfiguration.setProperty(XMLGRAMMAR_POOL, grammarPool);
153         }
154 
155         fConfiguration.addRecognizedFeatures(RECOGNIZED_FEATURES);
156 
157     } // <init>(SymbolTable,XMLGrammarPool)
158 
159     //
160     // XMLReader methods
161     //
162 
163     /**
164      * Parses the input source specified by the given system identifier.
165      * <p>
166      * This method is equivalent to the following:
167      * <pre>
168      *     parse(new InputSource(systemId));
169      * </pre>
170      *
171      * @param systemId The system identifier (URI).
172      *
173      * @exception org.xml.sax.SAXException Throws exception on SAX error.
174      * @exception java.io.IOException Throws exception on i/o error.
175      */
176     public void parse(String systemId) throws SAXException, IOException {
177 
178         // parse document
179         XMLInputSource source = new XMLInputSource(null, systemId, null);
180         try {
181             parse(source);
182         }
183 
184         // wrap XNI exceptions as SAX exceptions
185         catch (XMLParseException e) {
186             Exception ex = e.getException();
187             if (ex == null) {
188                 // must be a parser exception; mine it for locator info and throw
189                 // a SAXParseException
190                 LocatorImpl locatorImpl = new LocatorImpl();
191                 locatorImpl.setPublicId(e.getPublicId());
192                 locatorImpl.setSystemId(e.getExpandedSystemId());
193                 locatorImpl.setLineNumber(e.getLineNumber());
194                 locatorImpl.setColumnNumber(e.getColumnNumber());
195                 throw new SAXParseException(e.getMessage(), locatorImpl);
196             }
197             if (ex instanceof SAXException) {
198                 // why did we create an XMLParseException?
199                 throw (SAXException)ex;
200             }
201             if (ex instanceof IOException) {
202                 throw (IOException)ex;
203             }
204             throw new SAXException(ex);
205         }
206         catch (XNIException e) {
207             e.printStackTrace();
208             Exception ex = e.getException();
209             if (ex == null) {
210                 throw new SAXException(e.getMessage());
211             }
212             if (ex instanceof SAXException) {
213                 throw (SAXException)ex;
214             }
215             if (ex instanceof IOException) {
216                 throw (IOException)ex;
217             }
218             throw new SAXException(ex);
219         }
220 
221     } // parse(String)
222 
223     /**
224      * parse
225      *
226      * @param inputSource
227      *
228      * @exception org.xml.sax.SAXException
229      * @exception java.io.IOException
230      */
231     public void parse(InputSource inputSource)
232         throws SAXException, IOException {
233 
234         // parse document
235         try {
236             XMLInputSource xmlInputSource =
237                 new XMLInputSource(inputSource.getPublicId(),
238                                    inputSource.getSystemId(),
239                                    null);
240             xmlInputSource.setByteStream(inputSource.getByteStream());
241             xmlInputSource.setCharacterStream(inputSource.getCharacterStream());
242             xmlInputSource.setEncoding(inputSource.getEncoding());
243             parse(xmlInputSource);
244         }
245 
246         // wrap XNI exceptions as SAX exceptions
247         catch (XMLParseException e) {
248             Exception ex = e.getException();
249             if (ex == null) {
250                 // must be a parser exception; mine it for locator info and throw
251                 // a SAXParseException
252                 LocatorImpl locatorImpl = new LocatorImpl();
253                 locatorImpl.setPublicId(e.getPublicId());
254                 locatorImpl.setSystemId(e.getExpandedSystemId());
255                 locatorImpl.setLineNumber(e.getLineNumber());
256                 locatorImpl.setColumnNumber(e.getColumnNumber());
257                 throw new SAXParseException(e.getMessage(), locatorImpl);
258             }
259             if (ex instanceof SAXException) {
260                 // why did we create an XMLParseException?
261                 throw (SAXException)ex;
262             }
263             if (ex instanceof IOException) {
264                 throw (IOException)ex;
265             }
266             throw new SAXException(ex);
267         }
268         catch (XNIException e) {
269             Exception ex = e.getException();
270             if (ex == null) {
271                 throw new SAXException(e.getMessage());
272             }
273             if (ex instanceof SAXException) {
274                 throw (SAXException)ex;
275             }
276             if (ex instanceof IOException) {
277                 throw (IOException)ex;
278             }
279             throw new SAXException(ex);
280         }
281 
282     } // parse(InputSource)
283 
284     /**
285      * Sets the resolver used to resolve external entities. The EntityResolver
286      * interface supports resolution of public and system identifiers.
287      *
288      * @param resolver The new entity resolver. Passing a null value will
289      *                 uninstall the currently installed resolver.
290      */
291     public void setEntityResolver(EntityResolver resolver) {
292 
293         try {
294             XMLEntityResolver xer = (XMLEntityResolver) fConfiguration.getProperty(ENTITY_RESOLVER);
295             if (fUseEntityResolver2 && resolver instanceof EntityResolver2) {
296                 if (xer instanceof EntityResolver2Wrapper) {
297                     EntityResolver2Wrapper er2w = (EntityResolver2Wrapper) xer;
298                     er2w.setEntityResolver((EntityResolver2) resolver);
299                 }
300                 else {
301                     fConfiguration.setProperty(ENTITY_RESOLVER,
302                             new EntityResolver2Wrapper((EntityResolver2) resolver));
303                 }
304             }
305             else {
306                 if (xer instanceof EntityResolverWrapper) {
307                     EntityResolverWrapper erw = (EntityResolverWrapper) xer;
308                     erw.setEntityResolver(resolver);
309                 }
310                 else {
311                     fConfiguration.setProperty(ENTITY_RESOLVER,
312                             new EntityResolverWrapper(resolver));
313                 }
314             }
315         }
316         catch (XMLConfigurationException e) {
317             // do nothing
318         }
319 
320     } // setEntityResolver(EntityResolver)
321 
322     /**
323      * Return the current entity resolver.
324      *
325      * @return The current entity resolver, or null if none
326      *         has been registered.
327      * @see #setEntityResolver
328      */
329     public EntityResolver getEntityResolver() {
330 
331         EntityResolver entityResolver = null;
332         try {
333             XMLEntityResolver xmlEntityResolver =
334                 (XMLEntityResolver)fConfiguration.getProperty(ENTITY_RESOLVER);
335             if (xmlEntityResolver != null) {
336                 if (xmlEntityResolver instanceof EntityResolverWrapper) {
337                     entityResolver =
338                         ((EntityResolverWrapper) xmlEntityResolver).getEntityResolver();
339                 }
340                 else if (xmlEntityResolver instanceof EntityResolver2Wrapper) {
341                     entityResolver =
342                         ((EntityResolver2Wrapper) xmlEntityResolver).getEntityResolver();
343                 }
344             }
345         }
346         catch (XMLConfigurationException e) {
347             // do nothing
348         }
349         return entityResolver;
350 
351     } // getEntityResolver():EntityResolver
352 
353     /**
354      * Allow an application to register an error event handler.
355      *
356      * <p>If the application does not register an error handler, all
357      * error events reported by the SAX parser will be silently
358      * ignored; however, normal processing may not continue.  It is
359      * highly recommended that all SAX applications implement an
360      * error handler to avoid unexpected bugs.</p>
361      *
362      * <p>Applications may register a new or different handler in the
363      * middle of a parse, and the SAX parser must begin using the new
364      * handler immediately.</p>
365      *
366      * @param errorHandler The error handler.
367      * @exception java.lang.NullPointerException If the handler
368      *            argument is null.
369      * @see #getErrorHandler
370      */
371     public void setErrorHandler(ErrorHandler errorHandler) {
372 
373         try {
374             XMLErrorHandler xeh = (XMLErrorHandler) fConfiguration.getProperty(ERROR_HANDLER);
375             if (xeh instanceof ErrorHandlerWrapper) {
376                 ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh;
377                 ehw.setErrorHandler(errorHandler);
378             }
379             else {
380                 fConfiguration.setProperty(ERROR_HANDLER,
381                         new ErrorHandlerWrapper(errorHandler));
382             }
383         }
384         catch (XMLConfigurationException e) {
385             // do nothing
386         }
387 
388     } // setErrorHandler(ErrorHandler)
389 
390     /**
391      * Return the current error handler.
392      *
393      * @return The current error handler, or null if none
394      *         has been registered.
395      * @see #setErrorHandler
396      */
397     public ErrorHandler getErrorHandler() {
398 
399         ErrorHandler errorHandler = null;
400         try {
401             XMLErrorHandler xmlErrorHandler =
402                 (XMLErrorHandler)fConfiguration.getProperty(ERROR_HANDLER);
403             if (xmlErrorHandler != null &&
404                 xmlErrorHandler instanceof ErrorHandlerWrapper) {
405                 errorHandler = ((ErrorHandlerWrapper)xmlErrorHandler).getErrorHandler();
406             }
407         }
408         catch (XMLConfigurationException e) {
409             // do nothing
410         }
411         return errorHandler;
412 
413     } // getErrorHandler():ErrorHandler
414 
415     /**
416      * Set the state of any feature in a SAX2 parser.  The parser
417      * might not recognize the feature, and if it does recognize
418      * it, it might not be able to fulfill the request.
419      *
420      * @param featureId The unique identifier (URI) of the feature.
421      * @param state The requested state of the feature (true or false).
422      *
423      * @exception SAXNotRecognizedException If the
424      *            requested feature is not known.
425      * @exception SAXNotSupportedException If the
426      *            requested feature is known, but the requested
427      *            state is not supported.
428      */
429     public void setFeature(String featureId, boolean state)
430         throws SAXNotRecognizedException, SAXNotSupportedException {
431 
432         try {
433 
434             // http://xml.org/sax/features/use-entity-resolver2
435             //   controls whether the methods of an object implementing
436             //   org.xml.sax.ext.EntityResolver2 will be used by the parser.
437             //
438             if (featureId.equals(USE_ENTITY_RESOLVER2)) {
439                 if (state != fUseEntityResolver2) {
440                     fUseEntityResolver2 = state;
441                     // Refresh EntityResolver wrapper.
442                     setEntityResolver(getEntityResolver());
443                 }
444                 return;
445             }
446 
447             //
448             // Default handling
449             //
450 
451             fConfiguration.setFeature(featureId, state);
452         }
453         catch (XMLConfigurationException e) {
454             String identifier = e.getIdentifier();
455             if (e.getType() == Status.NOT_RECOGNIZED) {
456                 throw new SAXNotRecognizedException(
457                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
458                     "feature-not-recognized", new Object [] {identifier}));
459             }
460             else {
461                 throw new SAXNotSupportedException(
462                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
463                     "feature-not-supported", new Object [] {identifier}));
464             }
465         }
466 
467     } // setFeature(String,boolean)
468 
469     /**
470      * Query the state of a feature.
471      *
472      * Query the current state of any feature in a SAX2 parser.  The
473      * parser might not recognize the feature.
474      *
475      * @param featureId The unique identifier (URI) of the feature
476      *                  being set.
477      * @return The current state of the feature.
478      * @exception org.xml.sax.SAXNotRecognizedException If the
479      *            requested feature is not known.
480      * @exception SAXNotSupportedException If the
481      *            requested feature is known but not supported.
482      */
483     public boolean getFeature(String featureId)
484         throws SAXNotRecognizedException, SAXNotSupportedException {
485 
486         try {
487 
488             // http://xml.org/sax/features/use-entity-resolver2
489             //   controls whether the methods of an object implementing
490             //   org.xml.sax.ext.EntityResolver2 will be used by the parser.
491             //
492             if (featureId.equals(USE_ENTITY_RESOLVER2)) {
493                 return fUseEntityResolver2;
494             }
495 
496             //
497             // Default handling
498             //
499 
500             return fConfiguration.getFeature(featureId);
501         }
502         catch (XMLConfigurationException e) {
503             String identifier = e.getIdentifier();
504             if (e.getType() == Status.NOT_RECOGNIZED) {
505                 throw new SAXNotRecognizedException(
506                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
507                     "feature-not-recognized", new Object [] {identifier}));
508             }
509             else {
510                 throw new SAXNotSupportedException(
511                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
512                     "feature-not-supported", new Object [] {identifier}));
513             }
514         }
515 
516     } // getFeature(String):boolean
517 
518     /**
519      * Set the value of any property in a SAX2 parser.  The parser
520      * might not recognize the property, and if it does recognize
521      * it, it might not support the requested value.
522      *
523      * @param propertyId The unique identifier (URI) of the property
524      *                   being set.
525      * @param value The value to which the property is being set.
526      *
527      * @exception SAXNotRecognizedException If the
528      *            requested property is not known.
529      * @exception SAXNotSupportedException If the
530      *            requested property is known, but the requested
531      *            value is not supported.
532      */
533     public void setProperty(String propertyId, Object value)
534         throws SAXNotRecognizedException, SAXNotSupportedException {
535         /**
536          * It's possible for users to set a security manager through the interface.
537          * If it's the old SecurityManager, convert it to the new XMLSecurityManager
538          */
539         if (propertyId.equals(Constants.SECURITY_MANAGER)) {
540             securityManager = XMLSecurityManager.convert(value, securityManager);
541             setProperty0(Constants.SECURITY_MANAGER, securityManager);
542             return;
543         }
544         if (propertyId.equals(Constants.XML_SECURITY_PROPERTY_MANAGER)) {
545             if (value == null) {
546                 securityPropertyManager = new XMLSecurityPropertyManager();
547             } else {
548                 securityPropertyManager = (XMLSecurityPropertyManager)value;
549             }
550             setProperty0(Constants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager);
551             return;
552         }
553 
554         if (securityManager == null) {
555             securityManager = new XMLSecurityManager(true);
556             setProperty0(Constants.SECURITY_MANAGER, securityManager);
557         }
558 
559         if (securityPropertyManager == null) {
560             securityPropertyManager = new XMLSecurityPropertyManager();
561             setProperty0(Constants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager);
562         }
563         int index = securityPropertyManager.getIndex(propertyId);
564 
565         if (index > -1) {
566             /**
567              * this is a direct call to this parser, not a subclass since
568              * internally the support of this property is done through
569              * XMLSecurityPropertyManager
570              */
571             securityPropertyManager.setValue(index, XMLSecurityPropertyManager.State.APIPROPERTY, (String)value);
572         } else {
573             //check if the property is managed by security manager
574             if (!securityManager.setLimit(propertyId, XMLSecurityManager.State.APIPROPERTY, value)) {
575                 //fall back to the default configuration to handle the property
576                 setProperty0(propertyId, value);
577             }
578         }
579     }
580 
581     public void setProperty0(String propertyId, Object value)
582         throws SAXNotRecognizedException, SAXNotSupportedException {
583         try {
584             fConfiguration.setProperty(propertyId, value);
585         }
586         catch (XMLConfigurationException e) {
587             String identifier = e.getIdentifier();
588             if (e.getType() == Status.NOT_RECOGNIZED) {
589                 throw new SAXNotRecognizedException(
590                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
591                     "property-not-recognized", new Object [] {identifier}));
592             }
593             else {
594                 throw new SAXNotSupportedException(
595                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
596                     "property-not-supported", new Object [] {identifier}));
597             }
598         }
599 
600     } // setProperty(String,Object)
601 
602     /**
603      * Query the value of a property.
604      *
605      * Return the current value of a property in a SAX2 parser.
606      * The parser might not recognize the property.
607      *
608      * @param propertyId The unique identifier (URI) of the property
609      *                   being set.
610      * @return The current value of the property.
611      * @exception org.xml.sax.SAXNotRecognizedException If the
612      *            requested property is not known.
613      * @exception SAXNotSupportedException If the
614      *            requested property is known but not supported.
615      */
616     public Object getProperty(String propertyId)
617         throws SAXNotRecognizedException, SAXNotSupportedException {
618 
619        if (propertyId.equals(CURRENT_ELEMENT_NODE)) {
620            boolean deferred = false;
621            try {
622                deferred = getFeature(DEFER_NODE_EXPANSION);
623            }
624            catch (XMLConfigurationException e){
625                // ignore
626            }
627            if (deferred) {
628                throw new SAXNotSupportedException("Current element node cannot be queried when node expansion is deferred.");
629            }
630            return (fCurrentNode!=null &&
631                    fCurrentNode.getNodeType() == Node.ELEMENT_NODE)? fCurrentNode:null;
632        }
633 
634         try {
635             XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager)
636                     fConfiguration.getProperty(XML_SECURITY_PROPERTY_MANAGER);
637             int index = spm.getIndex(propertyId);
638             if (index > -1) {
639                 return spm.getValueByIndex(index);
640             }
641 
642             return fConfiguration.getProperty(propertyId);
643         }
644         catch (XMLConfigurationException e) {
645             String identifier = e.getIdentifier();
646             if (e.getType() == Status.NOT_RECOGNIZED) {
647                 throw new SAXNotRecognizedException(
648                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
649                     "property-not-recognized", new Object [] {identifier}));
650             }
651             else {
652                 throw new SAXNotSupportedException(
653                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
654                     "property-not-supported", new Object [] {identifier}));
655             }
656         }
657 
658     } // getProperty(String):Object
659 
660     /**
661      * Returns this parser's XMLParserConfiguration.
662      */
663     public XMLParserConfiguration getXMLParserConfiguration() {
664         return fConfiguration;
665     } // getXMLParserConfiguration():XMLParserConfiguration
666 
667 } // class DOMParser