View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 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  import java.util.ArrayList;
25  import java.util.HashMap;
26  import java.util.Locale;
27  
28  import com.sun.org.apache.xerces.internal.impl.Constants;
29  import com.sun.org.apache.xerces.internal.util.FeatureState;
30  import com.sun.org.apache.xerces.internal.util.ParserConfigurationSettings;
31  import com.sun.org.apache.xerces.internal.util.PropertyState;
32  import com.sun.org.apache.xerces.internal.util.Status;
33  import com.sun.org.apache.xerces.internal.util.SymbolTable;
34  import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
35  import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
36  import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
37  import com.sun.org.apache.xerces.internal.xni.XNIException;
38  import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
39  import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
40  import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
41  import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
42  import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
43  import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
44  import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
45  import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
46  
47  /**
48   * A very basic parser configuration. This configuration class can
49   * be used as a base class for custom parser configurations. The
50   * basic parser configuration creates the symbol table (if not
51   * specified at construction time) and manages all of the recognized
52   * features and properties.
53   * <p>
54   * The basic parser configuration does <strong>not</strong> mandate
55   * any particular pipeline configuration or the use of specific
56   * components except for the symbol table. If even this is too much
57   * for a basic parser configuration, the programmer can create a new
58   * configuration class that implements the
59   * <code>XMLParserConfiguration</code> interface.
60   * <p>
61   * Subclasses of the basic parser configuration can add their own
62   * recognized features and properties by calling the
63   * <code>addRecognizedFeature</code> and
64   * <code>addRecognizedProperty</code> methods, respectively.
65   * <p>
66   * The basic parser configuration assumes that the configuration
67   * will be made up of various parser components that implement the
68   * <code>XMLComponent</code> interface. If subclasses of this
69   * configuration create their own components for use in the
70   * parser configuration, then each component should be added to
71   * the list of components by calling the <code>addComponent</code>
72   * method. The basic parser configuration will make sure to call
73   * the <code>reset</code> method of each registered component
74   * before parsing an instance document.
75   * <p>
76   * This class recognizes the following features and properties:
77   * <ul>
78   * <li>Features
79   *  <ul>
80   *   <li>http://xml.org/sax/features/validation</li>;
81   *   <li>http://xml.org/sax/features/namespaces</li>;
82   *   <li>http://xml.org/sax/features/external-general-entities</li>;
83   *   <li>http://xml.org/sax/features/external-parameter-entities</li>;
84   *  </ul>
85   * <li>Properties
86   *  <ul>
87   *   <li>http://xml.org/sax/properties/xml-string</li>;
88   *   <li>http://apache.org/xml/properties/internal/symbol-table</li>;
89   *   <li>http://apache.org/xml/properties/internal/error-handler</li>;
90   *   <li>http://apache.org/xml/properties/internal/entity-resolver</li>;
91   *  </ul>
92   * </ul>
93   *
94   * @author Arnaud  Le Hors, IBM
95   * @author Andy Clark, IBM
96   *
97   * @version $Id: BasicParserConfiguration.java,v 1.6 2010-11-01 04:40:09 joehw Exp $
98   */
99  public abstract class BasicParserConfiguration
100     extends ParserConfigurationSettings
101     implements XMLParserConfiguration {
102 
103     //
104     // Constants
105     //
106 
107     // feature identifiers
108 
109     /** Feature identifier: validation. */
110     protected static final String VALIDATION =
111         Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
112 
113     /** Feature identifier: namespaces. */
114     protected static final String NAMESPACES =
115         Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
116 
117     /** Feature identifier: external general entities. */
118     protected static final String EXTERNAL_GENERAL_ENTITIES =
119         Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE;
120 
121     /** Feature identifier: external parameter entities. */
122     protected static final String EXTERNAL_PARAMETER_ENTITIES =
123         Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE;
124 
125     // property identifiers
126 
127     /** Property identifier: xml string. */
128     protected static final String XML_STRING =
129         Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY;
130 
131     /** Property identifier: symbol table. */
132     protected static final String SYMBOL_TABLE =
133         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
134 
135     /** Property identifier: error handler. */
136     protected static final String ERROR_HANDLER =
137         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
138 
139     /** Property identifier: entity resolver. */
140     protected static final String ENTITY_RESOLVER =
141         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
142 
143     //
144     // Data
145     //
146 
147     // components (non-configurable)
148 
149     /** Symbol table. */
150     protected SymbolTable fSymbolTable;
151 
152 
153     // data
154 
155     /** Locale. */
156     protected Locale fLocale;
157 
158     /** Components. */
159     protected ArrayList fComponents;
160 
161     // handlers
162 
163     /** The document handler. */
164     protected XMLDocumentHandler fDocumentHandler;
165 
166     /** The DTD handler. */
167     protected XMLDTDHandler fDTDHandler;
168 
169     /** The DTD content model handler. */
170     protected XMLDTDContentModelHandler fDTDContentModelHandler;
171 
172     /** Last component in the document pipeline */
173     protected XMLDocumentSource fLastComponent;
174 
175     //
176     // Constructors
177     //
178 
179     /** Default Constructor. */
180     protected BasicParserConfiguration() {
181         this(null, null);
182     } // <init>()
183 
184     /**
185      * Constructs a parser configuration using the specified symbol table.
186      *
187      * @param symbolTable The symbol table to use.
188      */
189     protected BasicParserConfiguration(SymbolTable symbolTable) {
190         this(symbolTable, null);
191     } // <init>(SymbolTable)
192 
193     /**
194      * Constructs a parser configuration using the specified symbol table
195      * and parent settings.
196      *
197      * @param symbolTable    The symbol table to use.
198      * @param parentSettings The parent settings.
199      */
200     protected BasicParserConfiguration(SymbolTable symbolTable,
201                                        XMLComponentManager parentSettings) {
202         super(parentSettings);
203 
204         // create a vector to hold all the components in use
205         fComponents = new ArrayList();
206 
207         // create table for features and properties
208         fFeatures = new HashMap();
209         fProperties = new HashMap();
210 
211         // add default recognized features
212         final String[] recognizedFeatures = {
213                 PARSER_SETTINGS,
214             VALIDATION,
215             NAMESPACES,
216             EXTERNAL_GENERAL_ENTITIES,
217             EXTERNAL_PARAMETER_ENTITIES,
218         };
219         addRecognizedFeatures(recognizedFeatures);
220         fFeatures.put(PARSER_SETTINGS, Boolean.TRUE);
221         // set state for default features
222                 fFeatures.put(VALIDATION, Boolean.FALSE);
223                 fFeatures.put(NAMESPACES, Boolean.TRUE);
224                 fFeatures.put(EXTERNAL_GENERAL_ENTITIES, Boolean.TRUE);
225                 fFeatures.put(EXTERNAL_PARAMETER_ENTITIES, Boolean.TRUE);
226 
227         // add default recognized properties
228         final String[] recognizedProperties = {
229             XML_STRING,
230             SYMBOL_TABLE,
231             ERROR_HANDLER,
232             ENTITY_RESOLVER,
233         };
234         addRecognizedProperties(recognizedProperties);
235 
236         if (symbolTable == null) {
237             symbolTable = new SymbolTable();
238         }
239         fSymbolTable = symbolTable;
240         fProperties.put(SYMBOL_TABLE, fSymbolTable);
241 
242     } // <init>(SymbolTable)
243 
244     /**
245      * Adds a component to the parser configuration. This method will
246      * also add all of the component's recognized features and properties
247      * to the list of default recognized features and properties.
248      *
249      * @param component The component to add.
250      */
251     protected void addComponent(XMLComponent component) {
252 
253         // don't add a component more than once
254         if (fComponents.contains(component)) {
255             return;
256         }
257         fComponents.add(component);
258 
259         // register component's recognized features
260         String[] recognizedFeatures = component.getRecognizedFeatures();
261         addRecognizedFeatures(recognizedFeatures);
262 
263         // register component's recognized properties
264         String[] recognizedProperties = component.getRecognizedProperties();
265         addRecognizedProperties(recognizedProperties);
266 
267         // set default values
268         if (recognizedFeatures != null) {
269             for (int i = 0; i < recognizedFeatures.length; i++) {
270                 String featureId = recognizedFeatures[i];
271                 Boolean state = component.getFeatureDefault(featureId);
272                 if (state != null) {
273                     super.setFeature(featureId, state.booleanValue());
274                 }
275             }
276         }
277         if (recognizedProperties != null) {
278             for (int i = 0; i < recognizedProperties.length; i++) {
279                 String propertyId = recognizedProperties[i];
280                 Object value = component.getPropertyDefault(propertyId);
281                 if (value != null) {
282                     super.setProperty(propertyId, value);
283                 }
284             }
285         }
286 
287     } // addComponent(XMLComponent)
288 
289     //
290     // XMLParserConfiguration methods
291     //
292 
293     /**
294      * Parse an XML document.
295      * <p>
296      * The parser can use this method to instruct this configuration
297      * to begin parsing an XML document from any valid input source
298      * (a character stream, a byte stream, or a URI).
299      * <p>
300      * Parsers may not invoke this method while a parse is in progress.
301      * Once a parse is complete, the parser may then parse another XML
302      * document.
303      * <p>
304      * This method is synchronous: it will not return until parsing
305      * has ended.  If a client application wants to terminate
306      * parsing early, it should throw an exception.
307      *
308      * @param inputSource The input source for the top-level of the
309      *               XML document.
310      *
311      * @exception XNIException Any XNI exception, possibly wrapping
312      *                         another exception.
313      * @exception IOException  An IO exception from the parser, possibly
314      *                         from a byte stream or character stream
315      *                         supplied by the parser.
316      */
317     public abstract void parse(XMLInputSource inputSource)
318         throws XNIException, IOException;
319 
320     /**
321      * Sets the document handler on the last component in the pipeline
322      * to receive information about the document.
323      *
324      * @param documentHandler   The document handler.
325      */
326     public void setDocumentHandler(XMLDocumentHandler documentHandler) {
327         fDocumentHandler = documentHandler;
328         if (fLastComponent != null) {
329             fLastComponent.setDocumentHandler(fDocumentHandler);
330             if (fDocumentHandler !=null){
331                 fDocumentHandler.setDocumentSource(fLastComponent);
332             }
333         }
334     } // setDocumentHandler(XMLDocumentHandler)
335 
336     /** Returns the registered document handler. */
337     public XMLDocumentHandler getDocumentHandler() {
338         return fDocumentHandler;
339     } // getDocumentHandler():XMLDocumentHandler
340 
341     /**
342      * Sets the DTD handler.
343      *
344      * @param dtdHandler The DTD handler.
345      */
346     public void setDTDHandler(XMLDTDHandler dtdHandler) {
347         fDTDHandler = dtdHandler;
348     } // setDTDHandler(XMLDTDHandler)
349 
350     /** Returns the registered DTD handler. */
351     public XMLDTDHandler getDTDHandler() {
352         return fDTDHandler;
353     } // getDTDHandler():XMLDTDHandler
354 
355     /**
356      * Sets the DTD content model handler.
357      *
358      * @param handler The DTD content model handler.
359      */
360     public void setDTDContentModelHandler(XMLDTDContentModelHandler handler) {
361         fDTDContentModelHandler = handler;
362     } // setDTDContentModelHandler(XMLDTDContentModelHandler)
363 
364     /** Returns the registered DTD content model handler. */
365     public XMLDTDContentModelHandler getDTDContentModelHandler() {
366         return fDTDContentModelHandler;
367     } // getDTDContentModelHandler():XMLDTDContentModelHandler
368 
369     /**
370      * Sets the resolver used to resolve external entities. The EntityResolver
371      * interface supports resolution of public and system identifiers.
372      *
373      * @param resolver The new entity resolver. Passing a null value will
374      *                 uninstall the currently installed resolver.
375      */
376     public void setEntityResolver(XMLEntityResolver resolver) {
377         // REVISIT: Should this be a property?
378         fProperties.put(ENTITY_RESOLVER, resolver);
379     } // setEntityResolver(XMLEntityResolver)
380 
381     /**
382      * Return the current entity resolver.
383      *
384      * @return The current entity resolver, or null if none
385      *         has been registered.
386      * @see #setEntityResolver
387      */
388     public XMLEntityResolver getEntityResolver() {
389         // REVISIT: Should this be a property?
390         return (XMLEntityResolver)fProperties.get(ENTITY_RESOLVER);
391     } // getEntityResolver():XMLEntityResolver
392 
393     /**
394      * Allow an application to register an error event handler.
395      *
396      * <p>If the application does not register an error handler, all
397      * error events reported by the SAX parser will be silently
398      * ignored; however, normal processing may not continue.  It is
399      * highly recommended that all SAX applications implement an
400      * error handler to avoid unexpected bugs.</p>
401      *
402      * <p>Applications may register a new or different handler in the
403      * middle of a parse, and the SAX parser must begin using the new
404      * handler immediately.</p>
405      *
406      * @param errorHandler The error handler.
407      * @exception java.lang.NullPointerException If the handler
408      *            argument is null.
409      * @see #getErrorHandler
410      */
411     public void setErrorHandler(XMLErrorHandler errorHandler) {
412         // REVISIT: Should this be a property?
413         fProperties.put(ERROR_HANDLER, errorHandler);
414     } // setErrorHandler(XMLErrorHandler)
415 
416     /**
417      * Return the current error handler.
418      *
419      * @return The current error handler, or null if none
420      *         has been registered.
421      * @see #setErrorHandler
422      */
423     public XMLErrorHandler getErrorHandler() {
424         // REVISIT: Should this be a property?
425         return (XMLErrorHandler)fProperties.get(ERROR_HANDLER);
426     } // getErrorHandler():XMLErrorHandler
427 
428     /**
429      * Set the state of a feature.
430      *
431      * Set the state of any feature in a SAX2 parser.  The parser
432      * might not recognize the feature, and if it does recognize
433      * it, it might not be able to fulfill the request.
434      *
435      * @param featureId The unique identifier (URI) of the feature.
436      * @param state The requested state of the feature (true or false).
437      *
438      * @exception com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException If the
439      *            requested feature is not known.
440      */
441     public void setFeature(String featureId, boolean state)
442         throws XMLConfigurationException {
443 
444         // forward to every component
445         int count = fComponents.size();
446         for (int i = 0; i < count; i++) {
447             XMLComponent c = (XMLComponent) fComponents.get(i);
448             c.setFeature(featureId, state);
449         }
450         // save state if noone "objects"
451         super.setFeature(featureId, state);
452 
453     } // setFeature(String,boolean)
454 
455     /**
456      * setProperty
457      *
458      * @param propertyId
459      * @param value
460      */
461     public void setProperty(String propertyId, Object value)
462         throws XMLConfigurationException {
463 
464         // forward to every component
465         int count = fComponents.size();
466         for (int i = 0; i < count; i++) {
467             XMLComponent c = (XMLComponent) fComponents.get(i);
468             c.setProperty(propertyId, value);
469         }
470 
471         // store value if noone "objects"
472         super.setProperty(propertyId, value);
473 
474     } // setProperty(String,Object)
475 
476     /**
477      * Set the locale to use for messages.
478      *
479      * @param locale The locale object to use for localization of messages.
480      *
481      * @exception XNIException Thrown if the parser does not support the
482      *                         specified locale.
483      */
484     public void setLocale(Locale locale) throws XNIException {
485         fLocale = locale;
486     } // setLocale(Locale)
487 
488     /** Returns the locale. */
489     public Locale getLocale() {
490         return fLocale;
491     } // getLocale():Locale
492 
493     //
494     // Protected methods
495     //
496 
497     /**
498      * reset all components before parsing and namespace context
499      */
500     protected void reset() throws XNIException {
501 
502         // reset every component
503         int count = fComponents.size();
504         for (int i = 0; i < count; i++) {
505             XMLComponent c = (XMLComponent) fComponents.get(i);
506             c.reset(this);
507         }
508 
509     } // reset()
510 
511     /**
512      * Check a property. If the property is known and supported, this method
513      * simply returns. Otherwise, the appropriate exception is thrown.
514      *
515      * @param propertyId The unique identifier (URI) of the property
516      *                   being set.
517      * @exception com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException If the
518      *            requested feature is not known or supported.
519      */
520     protected PropertyState checkProperty(String propertyId)
521         throws XMLConfigurationException {
522 
523         // special cases
524         if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) {
525             final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length();
526 
527             //
528             // http://xml.org/sax/properties/xml-string
529             // Value type: String
530             // Access: read-only
531             //   Get the literal string of characters associated with the
532             //   current event.  If the parser recognises and supports this
533             //   property but is not currently parsing text, it should return
534             //   null (this is a good way to check for availability before the
535             //   parse begins).
536             //
537             if (suffixLength == Constants.XML_STRING_PROPERTY.length() &&
538                 propertyId.endsWith(Constants.XML_STRING_PROPERTY)) {
539                 // REVISIT - we should probably ask xml-dev for a precise
540                 // definition of what this is actually supposed to return, and
541                 // in exactly which circumstances.
542                 return PropertyState.NOT_SUPPORTED;
543             }
544         }
545 
546         // check property
547         return super.checkProperty(propertyId);
548 
549     } // checkProperty(String)
550 
551 
552     /**
553      * Check a feature. If feature is know and supported, this method simply
554      * returns. Otherwise, the appropriate exception is thrown.
555      *
556      * @param featureId The unique identifier (URI) of the feature.
557      *
558      * @throws XMLConfigurationException Thrown for configuration error.
559      *                                   In general, components should
560      *                                   only throw this exception if
561      *                                   it is <strong>really</strong>
562      *                                   a critical error.
563      */
564     protected FeatureState checkFeature(String featureId)
565         throws XMLConfigurationException {
566 
567         //
568         // Xerces Features
569         //
570         if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) {
571             final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length();
572 
573             //
574             // special performance feature: no one by component manager is allowed to set it
575             //
576             if (suffixLength == Constants.PARSER_SETTINGS.length() &&
577                 featureId.endsWith(Constants.PARSER_SETTINGS)) {
578                 return FeatureState.NOT_SUPPORTED;
579             }
580         }
581 
582         return super.checkFeature(featureId);
583      } // checkFeature(String)
584 
585 
586 } // class BasicParserConfiguration