1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999-2003 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.impl.dtd;
  58. import com.sun.org.apache.xerces.internal.impl.Constants;
  59. import com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl;
  60. import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  61. import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  62. import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  63. import com.sun.org.apache.xerces.internal.util.SymbolTable;
  64. import com.sun.org.apache.xerces.internal.util.DefaultErrorHandler;
  65. import com.sun.org.apache.xerces.internal.xni.XNIException;
  66. import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  67. import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarLoader;
  68. import com.sun.org.apache.xerces.internal.xni.grammars.Grammar;
  69. import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  70. import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
  71. import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
  72. import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  73. import java.util.Locale;
  74. import java.io.IOException;
  75. import java.io.EOFException;
  76. /**
  77. * The DTD loader. The loader knows how to build grammars from XMLInputSources.
  78. * It extends the DTD processor in order to do this; it's
  79. * a separate class because DTD processors don't need to know how
  80. * to talk to the outside world in their role as instance-document
  81. * helpers.
  82. * <p>
  83. * This component requires the following features and properties. It
  84. * know ho to set them if no one else does:from the
  85. * <ul>
  86. * <li>http://xml.org/sax/features/namespaces</li>
  87. * <li>http://apache.org/xml/properties/internal/symbol-table</li>
  88. * <li>http://apache.org/xml/properties/internal/error-reporter</li>
  89. * <li>http://apache.org/xml/properties/internal/grammar-pool</li>
  90. * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li>
  91. * </ul>
  92. *
  93. * @author Neil Graham, IBM
  94. *
  95. * @version $Id: XMLDTDLoader.java,v 1.9 2003/10/14 14:34:26 mrglavas Exp $
  96. */
  97. public class XMLDTDLoader
  98. extends XMLDTDProcessor
  99. implements XMLGrammarLoader {
  100. //
  101. // Constants
  102. //
  103. // feature identifiers
  104. /** Feature identifier: standard uri conformant feature. */
  105. protected static final String STANDARD_URI_CONFORMANT_FEATURE =
  106. Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
  107. // recognized features:
  108. private static final String[] RECOGNIZED_FEATURES = {
  109. VALIDATION,
  110. WARN_ON_DUPLICATE_ATTDEF,
  111. NOTIFY_CHAR_REFS,
  112. STANDARD_URI_CONFORMANT_FEATURE
  113. };
  114. // property identifiers
  115. /** Property identifier: error handler. */
  116. protected static final String ERROR_HANDLER =
  117. Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
  118. /** Property identifier: entity resolver. */
  119. public static final String ENTITY_RESOLVER =
  120. Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
  121. /** Recognized properties. */
  122. private static final String[] LOADER_RECOGNIZED_PROPERTIES = {
  123. SYMBOL_TABLE,
  124. ERROR_REPORTER,
  125. ERROR_HANDLER,
  126. ENTITY_RESOLVER,
  127. GRAMMAR_POOL,
  128. DTD_VALIDATOR,
  129. };
  130. // enforcing strict uri?
  131. private boolean fStrictURI = false;
  132. /** Entity resolver . */
  133. protected XMLEntityResolver fEntityResolver;
  134. // the scanner we use to actually read the DTD
  135. protected XMLDTDScannerImpl fDTDScanner;
  136. // the entity manager the scanner needs.
  137. protected XMLEntityManager fEntityManager;
  138. // what's our Locale?
  139. protected Locale fLocale;
  140. //
  141. // Constructors
  142. //
  143. /** Deny default construction; we need a SymtolTable! */
  144. public XMLDTDLoader() {
  145. this(new SymbolTable());
  146. } // <init>()
  147. public XMLDTDLoader(SymbolTable symbolTable) {
  148. this(symbolTable, null);
  149. } // init(SymbolTable)
  150. public XMLDTDLoader(SymbolTable symbolTable,
  151. XMLGrammarPool grammarPool) {
  152. this(symbolTable, grammarPool, null, new XMLEntityManager());
  153. } // init(SymbolTable, XMLGrammarPool)
  154. XMLDTDLoader(SymbolTable symbolTable,
  155. XMLGrammarPool grammarPool, XMLErrorReporter errorReporter,
  156. XMLEntityResolver entityResolver) {
  157. fSymbolTable = symbolTable;
  158. fGrammarPool = grammarPool;
  159. if(errorReporter == null) {
  160. errorReporter = new XMLErrorReporter();
  161. errorReporter.setProperty(ERROR_HANDLER, new DefaultErrorHandler());
  162. }
  163. fErrorReporter = errorReporter;
  164. // Add XML message formatter if there isn't one.
  165. if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) {
  166. XMLMessageFormatter xmft = new XMLMessageFormatter();
  167. fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft);
  168. fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft);
  169. }
  170. fEntityResolver = entityResolver;
  171. if(fEntityResolver instanceof XMLEntityManager) {
  172. fEntityManager = (XMLEntityManager)fEntityResolver;
  173. } else {
  174. fEntityManager = new XMLEntityManager();
  175. }
  176. fEntityManager.setProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY, errorReporter);
  177. fDTDScanner = new XMLDTDScannerImpl(fSymbolTable, fErrorReporter, fEntityManager);
  178. fDTDScanner.setDTDHandler(this);
  179. fDTDScanner.setDTDContentModelHandler(this);
  180. reset();
  181. } // init(SymbolTable, XMLGrammarPool, XMLErrorReporter, XMLEntityResolver)
  182. // XMLGrammarLoader methods
  183. /**
  184. * Sets the state of a feature. This method is called by the component
  185. * manager any time after reset when a feature changes state.
  186. * <p>
  187. * <strong>Note:</strong> Components should silently ignore features
  188. * that do not affect the operation of the component.
  189. *
  190. * @param featureId The feature identifier.
  191. * @param state The state of the feature.
  192. *
  193. * @throws SAXNotRecognizedException The component should not throw
  194. * this exception.
  195. * @throws SAXNotSupportedException The component should not throw
  196. * this exception.
  197. */
  198. public void setFeature(String featureId, boolean state)
  199. throws XMLConfigurationException {
  200. if(featureId.equals(VALIDATION)) {
  201. fValidation = state;
  202. } else if(featureId.equals(WARN_ON_DUPLICATE_ATTDEF)) {
  203. fWarnDuplicateAttdef = state;
  204. } else if(featureId.equals(NOTIFY_CHAR_REFS)) {
  205. fDTDScanner.setFeature(featureId, state);
  206. } else if(featureId.equals(STANDARD_URI_CONFORMANT_FEATURE)) {
  207. fStrictURI = state;
  208. } else {
  209. throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, featureId);
  210. }
  211. } // setFeature(String,boolean)
  212. /**
  213. * Returns a list of property identifiers that are recognized by
  214. * this component. This method may return null if no properties
  215. * are recognized by this component.
  216. */
  217. public String[] getRecognizedProperties() {
  218. return (String[])(LOADER_RECOGNIZED_PROPERTIES.clone());
  219. } // getRecognizedProperties():String[]
  220. /**
  221. * Returns the state of a property.
  222. *
  223. * @param propertyId The property identifier.
  224. *
  225. * @throws XMLConfigurationException Thrown on configuration error.
  226. */
  227. public Object getProperty(String propertyId)
  228. throws XMLConfigurationException {
  229. if(propertyId.equals( SYMBOL_TABLE)) {
  230. return fSymbolTable;
  231. } else if(propertyId.equals( ERROR_REPORTER)) {
  232. return fErrorReporter;
  233. } else if(propertyId.equals( ERROR_HANDLER)) {
  234. return fErrorReporter.getErrorHandler();
  235. } else if(propertyId.equals( ENTITY_RESOLVER)) {
  236. return fEntityResolver;
  237. } else if(propertyId.equals( GRAMMAR_POOL)) {
  238. return fGrammarPool;
  239. } else if(propertyId.equals( DTD_VALIDATOR)) {
  240. return fValidator;
  241. }
  242. throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, propertyId);
  243. } // getProperty(String): Object
  244. /**
  245. * Sets the value of a property. This method is called by the component
  246. * manager any time after reset when a property changes value.
  247. * <p>
  248. * <strong>Note:</strong> Components should silently ignore properties
  249. * that do not affect the operation of the component.
  250. *
  251. * @param propertyId The property identifier.
  252. * @param value The value of the property.
  253. *
  254. * @throws SAXNotRecognizedException The component should not throw
  255. * this exception.
  256. * @throws SAXNotSupportedException The component should not throw
  257. * this exception.
  258. */
  259. public void setProperty(String propertyId, Object value)
  260. throws XMLConfigurationException {
  261. if(propertyId.equals( SYMBOL_TABLE)) {
  262. fSymbolTable = (SymbolTable)value;
  263. fDTDScanner.setProperty(propertyId, value);
  264. fEntityManager.setProperty(propertyId, value);
  265. } else if(propertyId.equals( ERROR_REPORTER)) {
  266. fErrorReporter = (XMLErrorReporter)value;
  267. // Add XML message formatter if there isn't one.
  268. if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) {
  269. XMLMessageFormatter xmft = new XMLMessageFormatter();
  270. fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft);
  271. fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft);
  272. }
  273. fDTDScanner.setProperty(propertyId, value);
  274. fEntityManager.setProperty(propertyId, value);
  275. } else if(propertyId.equals( ERROR_HANDLER)) {
  276. fErrorReporter.setProperty(propertyId, value);
  277. } else if(propertyId.equals( ENTITY_RESOLVER)) {
  278. fEntityResolver = (XMLEntityResolver)value;
  279. } else if(propertyId.equals( GRAMMAR_POOL)) {
  280. fGrammarPool = (XMLGrammarPool)value;
  281. } else {
  282. throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, propertyId);
  283. }
  284. } // setProperty(String,Object)
  285. /**
  286. * Returns the state of a feature.
  287. *
  288. * @param featureId The feature identifier.
  289. *
  290. * @throws XMLConfigurationException Thrown on configuration error.
  291. */
  292. public boolean getFeature(String featureId)
  293. throws XMLConfigurationException {
  294. if(featureId.equals( VALIDATION)) {
  295. return fValidation;
  296. } else if(featureId.equals( WARN_ON_DUPLICATE_ATTDEF)) {
  297. return fWarnDuplicateAttdef;
  298. } else if(featureId.equals( NOTIFY_CHAR_REFS)) {
  299. return fDTDScanner.getFeature(featureId);
  300. }
  301. throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, featureId);
  302. } //getFeature(String): boolean
  303. /**
  304. * Set the locale to use for messages.
  305. *
  306. * @param locale The locale object to use for localization of messages.
  307. *
  308. * @exception XNIException Thrown if the parser does not support the
  309. * specified locale.
  310. */
  311. public void setLocale(Locale locale) {
  312. fLocale = locale;
  313. } // setLocale(Locale)
  314. /** Return the Locale the XMLGrammarLoader is using. */
  315. public Locale getLocale() {
  316. return fLocale;
  317. } // getLocale(): Locale
  318. /**
  319. * Sets the error handler.
  320. *
  321. * @param errorHandler The error handler.
  322. */
  323. public void setErrorHandler(XMLErrorHandler errorHandler) {
  324. fErrorReporter.setProperty(ERROR_HANDLER, errorHandler);
  325. } // setErrorHandler(XMLErrorHandler)
  326. /** Returns the registered error handler. */
  327. public XMLErrorHandler getErrorHandler() {
  328. return fErrorReporter.getErrorHandler();
  329. } // getErrorHandler(): XMLErrorHandler
  330. /**
  331. * Sets the entity resolver.
  332. *
  333. * @param entityResolver The new entity resolver.
  334. */
  335. public void setEntityResolver(XMLEntityResolver entityResolver) {
  336. fEntityResolver = entityResolver;
  337. } // setEntityResolver(XMLEntityResolver)
  338. /** Returns the registered entity resolver. */
  339. public XMLEntityResolver getEntityResolver() {
  340. return fEntityResolver;
  341. } // getEntityResolver(): XMLEntityResolver
  342. /**
  343. * Returns a Grammar object by parsing the contents of the
  344. * entity pointed to by source.
  345. *
  346. * @param source the location of the entity which forms
  347. * the starting point of the grammar to be constructed.
  348. * @throws IOException When a problem is encountered reading the entity
  349. * XNIException When a condition arises (such as a FatalError) that requires parsing
  350. * of the entity be terminated.
  351. */
  352. public Grammar loadGrammar(XMLInputSource source)
  353. throws IOException, XNIException {
  354. reset();
  355. // First chance checking strict URI
  356. String eid = XMLEntityManager.expandSystemId(source.getSystemId(), source.getBaseSystemId(), fStrictURI);
  357. fDTDGrammar = new DTDGrammar(fSymbolTable, new XMLDTDDescription(source.getPublicId(), source.getSystemId(), source.getBaseSystemId(), eid, null));
  358. fGrammarBucket = new DTDGrammarBucket();
  359. fGrammarBucket.setStandalone(false);
  360. fGrammarBucket.setActiveGrammar(fDTDGrammar);
  361. // no reason to use grammar bucket's "put" method--we
  362. // know which grammar it is, and we don't know the root name anyway...
  363. // actually start the parsing!
  364. try {
  365. fDTDScanner.setInputSource(source);
  366. fDTDScanner.scanDTDExternalSubset(true);
  367. } catch (EOFException e) {
  368. // expected behaviour...
  369. }
  370. finally {
  371. // Close all streams opened by the parser.
  372. fEntityManager.closeReaders();
  373. }
  374. if(fDTDGrammar != null && fGrammarPool != null) {
  375. fGrammarPool.cacheGrammars(XMLDTDDescription.XML_DTD, new Grammar[] {fDTDGrammar});
  376. }
  377. return fDTDGrammar;
  378. } // loadGrammar(XMLInputSource): Grammar
  379. // reset all the components that we rely upon
  380. protected void reset() {
  381. super.reset();
  382. fDTDScanner.reset();
  383. fEntityManager.reset();
  384. fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner());
  385. }
  386. } // class XMLDTDLoader