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