1. /*
  2. *
  3. * The Apache Software License, Version 1.1
  4. *
  5. *
  6. * Copyright (c) 2000-2004 The Apache Software Foundation. All rights
  7. * reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. *
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. *
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in
  18. * the documentation and/or other materials provided with the
  19. * distribution.
  20. *
  21. * 3. The end-user documentation included with the redistribution,
  22. * if any, must include the following acknowledgment:
  23. * "This product includes software developed by the
  24. * Apache Software Foundation (http://www.apache.org/)."
  25. * Alternately, this acknowledgment may appear in the software itself,
  26. * if and wherever such third-party acknowledgments normally appear.
  27. *
  28. * 4. The names "Xerces" and "Apache Software Foundation" must
  29. * not be used to endorse or promote products derived from this
  30. * software without prior written permission. For written
  31. * permission, please contact apache@apache.org.
  32. *
  33. * 5. Products derived from this software may not be called "Apache",
  34. * nor may "Apache" appear in their name, without prior written
  35. * permission of the Apache Software Foundation.
  36. *
  37. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  38. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  39. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  40. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  41. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  42. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  43. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  44. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  45. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  46. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  47. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  48. * SUCH DAMAGE.
  49. * ====================================================================
  50. *
  51. * This software consists of voluntary contributions made by many
  52. * individuals on behalf of the Apache Software Foundation and was
  53. * originally based on software copyright (c) 1999, Sun Microsystems, Inc.,
  54. * http://www.sun.com. For more information on the Apache Software
  55. * Foundation, please see <http://www.apache.org/>.
  56. */
  57. package com.sun.org.apache.xerces.internal.jaxp;
  58. import java.util.Enumeration;
  59. import java.util.HashMap;
  60. import java.util.Hashtable;
  61. import javax.xml.parsers.SAXParserFactory;
  62. import javax.xml.validation.Schema;
  63. import com.sun.org.apache.xerces.internal.impl.Constants;
  64. import com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser;
  65. import com.sun.org.apache.xerces.internal.parsers.JAXPConfiguration;
  66. import org.xml.sax.SAXException;
  67. import org.xml.sax.SAXNotRecognizedException;
  68. import org.xml.sax.SAXNotSupportedException;
  69. import org.xml.sax.XMLReader;
  70. import com.sun.org.apache.xerces.internal.util.SecurityManager;
  71. import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter;
  72. import com.sun.org.apache.xerces.internal.xni.XNIException;
  73. import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
  74. /**
  75. * This is the implementation specific class for the
  76. * <code>javax.xml.parsers.SAXParser</code>.
  77. *
  78. * @author Rajiv Mordani
  79. * @author Edwin Goei
  80. *
  81. * @version $Id: SAXParserImpl.java,v 1.23 2004/02/24 23:15:58 mrglavas Exp $
  82. */
  83. public class SAXParserImpl extends javax.xml.parsers.SAXParser
  84. implements JAXPConstants {
  85. // Should XMLParserConfiguration have reset, ? we have reset at component level
  86. private final JAXPConfiguration parserConfiguration;
  87. private final AbstractSAXParser xmlReader;
  88. private String schemaLanguage = null; // null means DTD
  89. private final Schema grammar;
  90. private final SecurityManager secureProcessing;
  91. private boolean isXIncludeAware;
  92. private boolean enableSecureProcessing = true;
  93. //we have to keep the reference to features and SAXParserFactory so that
  94. //we can set the SAXParser to the same state when it
  95. //was createed from the factory.
  96. private Hashtable features;
  97. private SAXParserFactory spf;
  98. private Hashtable parserFeatures = new Hashtable();
  99. public boolean isXIncludeAware() {
  100. return isXIncludeAware;
  101. }
  102. /**
  103. * Create a SAX parser with the associated features
  104. * @param features Hashtable of SAX features, may be null
  105. */
  106. SAXParserImpl(SAXParserFactory spfactory, Hashtable factoryfeatures)
  107. throws SAXException
  108. {
  109. this.spf = spfactory ;
  110. this.features = factoryfeatures;
  111. // inherit
  112. secureProcessing = new SecurityManager();
  113. this.grammar = spf.getSchema();
  114. parserConfiguration = new JAXPConfiguration(grammar);
  115. xmlReader = new com.sun.org.apache.xerces.internal.parsers.SAXParser(parserConfiguration);
  116. //initialize the feature as per factory settings..
  117. init();
  118. }
  119. //initialize the features as per factory settings.
  120. void init() throws SAXNotSupportedException, SAXNotRecognizedException {
  121. Enumeration keys = parserFeatures.keys();
  122. while(keys.hasMoreElements()){
  123. String propertyId = (String)keys.nextElement();
  124. Object value = parserFeatures.get(propertyId);
  125. if(value instanceof Boolean){
  126. //this means it is a feature, we have to get default value from the configuration
  127. xmlReader.setFeature(propertyId, parserConfiguration.getFeatureDefaultValue(propertyId));
  128. }
  129. else{//it's a property
  130. //null value should delete the property from underlying implementation.
  131. xmlReader.setProperty(propertyId, null);
  132. }
  133. }
  134. //clear the hashtable once we have removed all the properties.
  135. parserFeatures.clear();
  136. schemaLanguage = null ;
  137. this.isXIncludeAware = spf.isXIncludeAware();
  138. if(features != null ){
  139. Object tmpValue = features.get(Constants.FEATURE_SECURE_PROCESSING);
  140. if( tmpValue != null )
  141. enableSecureProcessing = ((Boolean)tmpValue).booleanValue();
  142. }
  143. if(enableSecureProcessing){
  144. try {
  145. setProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY, secureProcessing);
  146. } catch (SAXNotRecognizedException sex) {
  147. sex.printStackTrace();
  148. } catch (SAXNotSupportedException se) {
  149. se.printStackTrace();
  150. }
  151. }
  152. xmlReader.setFeature(
  153. Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_AWARE,
  154. isXIncludeAware);
  155. // If validating, provide a default ErrorHandler that prints
  156. // validation errors with a warning telling the user to set an
  157. // ErrorHandler.
  158. if (spf.isValidating()) {
  159. xmlReader.setErrorHandler(new DefaultValidationErrorHandler());
  160. }
  161. xmlReader.setFeature(Constants.SAX_FEATURE_PREFIX +
  162. Constants.VALIDATION_FEATURE, spf.isValidating());
  163. // JAXP "namespaceAware" == SAX Namespaces feature
  164. // Note: there is a compatibility problem here with default values:
  165. // JAXP default is false while SAX 2 default is true!
  166. xmlReader.setFeature(Constants.SAX_FEATURE_PREFIX +
  167. Constants.NAMESPACES_FEATURE,
  168. spf.isNamespaceAware());
  169. // SAX "namespaces" and "namespace-prefixes" features should not
  170. // both be false. We make them opposite for backward compatibility
  171. // since JAXP 1.0 apps may want to receive xmlns* attributes.
  172. xmlReader.setFeature(Constants.SAX_FEATURE_PREFIX +
  173. Constants.NAMESPACE_PREFIXES_FEATURE,
  174. !spf.isNamespaceAware());
  175. setFeatures(features);
  176. }//init()
  177. /**
  178. * Set any features of our XMLReader based on any features set on the
  179. * SAXParserFactory.
  180. *
  181. * XXX Does not handle possible conflicts between SAX feature names and
  182. * JAXP specific feature names, eg. SAXParserFactory.isValidating()
  183. */
  184. private void setFeatures(Hashtable features)
  185. throws SAXNotSupportedException, SAXNotRecognizedException
  186. {
  187. if (features != null) {
  188. for (Enumeration e = features.keys(); e.hasMoreElements();) {
  189. String feature = (String)e.nextElement();
  190. boolean value = ((Boolean)features.get(feature)).booleanValue();
  191. if(!feature.equals(Constants.FEATURE_SECURE_PROCESSING))
  192. xmlReader.setFeature(feature, value);
  193. }
  194. }
  195. }
  196. /**
  197. * @deprecated
  198. */
  199. public org.xml.sax.Parser getParser() throws SAXException {
  200. return xmlReader;
  201. }
  202. /**
  203. * <p>Reset this <code>DocumentBuilder</code> to its original configuration.</p>
  204. *
  205. * <p><code>DocumentBuilder</code> is reset to the same state as when it was created with
  206. * {@link DocumentBuilderFactory#newDocumentBuilder()}.
  207. * <code>reset()</code> is designed to allow the reuse of existing <code>DocumentBuilder</code>s
  208. * thus saving resources associated with the creation of new <code>DocumentBuilder</code>s.</p>
  209. *
  210. * <p>The reset <code>DocumentBuilder</code> is not guaranteed to have the same {@link EntityResolver} or {@link ErrorHandler}
  211. * <code>Object</code>s, e.g. {@link Object#equals(Object obj)}. It is guaranteed to have a functionally equal
  212. * <code>EntityResolver</code> and <code>ErrorHandler</code>.</p>
  213. *
  214. * @since 1.5
  215. */
  216. public void reset(){
  217. if(xmlReader != null){
  218. try{
  219. //we dont need to worry about any properties being set on this object because
  220. //DocumentBuilder doesn't provide any way to set the properties
  221. //once it is created.
  222. xmlReader.reset();
  223. //set the object back to its factory settings
  224. init();
  225. }
  226. //xxx: underlying implementation reset throws XNIException what should we do in this case ?
  227. //if there was any propery that is not being supported
  228. //exception would have been thrown when setting it on the underlying implementation.
  229. catch(XNIException ex){
  230. //coninue.
  231. }
  232. catch(SAXException sax){}
  233. }
  234. }
  235. /**
  236. * Returns the XMLReader that is encapsulated by the implementation of
  237. * this class.
  238. */
  239. public XMLReader getXMLReader() {
  240. return xmlReader;
  241. }
  242. public boolean isNamespaceAware() {
  243. try {
  244. return xmlReader.getFeature(Constants.SAX_FEATURE_PREFIX +
  245. Constants.NAMESPACES_FEATURE);
  246. } catch (SAXException x) {
  247. throw new IllegalStateException(x.getMessage());
  248. }
  249. }
  250. public boolean isValidating() {
  251. try {
  252. return xmlReader.getFeature(Constants.SAX_FEATURE_PREFIX +
  253. Constants.VALIDATION_FEATURE);
  254. } catch (SAXException x) {
  255. throw new IllegalStateException(x.getMessage());
  256. }
  257. }
  258. /**
  259. * Sets the particular property in the underlying implementation of
  260. * org.xml.sax.XMLReader.
  261. */
  262. public void setProperty(String name, Object value)
  263. throws SAXNotRecognizedException, SAXNotSupportedException
  264. {
  265. // the spec says if a schema is given via SAXParserFactory
  266. // the JAXP 1.2 properties shouldn't be allowed. So
  267. // reject them first.
  268. if(grammar!=null) {
  269. if (JAXP_SCHEMA_LANGUAGE.equals(name)
  270. || JAXP_SCHEMA_SOURCE.equals(name)) {
  271. throw new SAXNotSupportedException(
  272. SAXMessageFormatter.formatMessage(null, "schema-already-specified", null));
  273. }
  274. }
  275. if (JAXP_SCHEMA_LANGUAGE.equals(name)) {
  276. // JAXP 1.2 support
  277. if ( W3C_XML_SCHEMA.equals(value) ) {
  278. //None of the properties will take effect till the setValidating(true) has been called
  279. if( isValidating() ) {
  280. schemaLanguage = W3C_XML_SCHEMA;
  281. xmlReader.setFeature(Constants.XERCES_FEATURE_PREFIX +
  282. Constants.SCHEMA_VALIDATION_FEATURE,
  283. true);
  284. //also set the schema full checking to true.
  285. xmlReader.setFeature(Constants.XERCES_FEATURE_PREFIX +
  286. Constants.SCHEMA_FULL_CHECKING,
  287. true);
  288. //add this among the list of parser features since this is added
  289. //on the parser instance and should be set to default value during
  290. //reset.
  291. parserFeatures.put(Constants.XERCES_FEATURE_PREFIX +
  292. Constants.SCHEMA_VALIDATION_FEATURE, new Boolean(true));
  293. parserFeatures.put(Constants.XERCES_FEATURE_PREFIX +
  294. Constants.SCHEMA_FULL_CHECKING, new Boolean(true));
  295. // this will allow the parser not to emit DTD-related
  296. // errors, as the spec demands
  297. xmlReader.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
  298. parserFeatures.put(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
  299. }
  300. } else if (value == null) {
  301. schemaLanguage = null;
  302. xmlReader.setFeature(Constants.XERCES_FEATURE_PREFIX +
  303. Constants.SCHEMA_VALIDATION_FEATURE,
  304. false);
  305. parserFeatures.put(Constants.XERCES_FEATURE_PREFIX +
  306. Constants.SCHEMA_VALIDATION_FEATURE,
  307. new Boolean(false));
  308. } else {
  309. // REVISIT: It would be nice if we could format this message
  310. // using a user specified locale as we do in the underlying
  311. // XMLReader -- mrglavas
  312. throw new SAXNotSupportedException(
  313. SAXMessageFormatter.formatMessage(null, "schema-not-supported", null));
  314. }
  315. }
  316. else if(JAXP_SCHEMA_SOURCE.equals(name)) {
  317. String val = (String)getProperty(JAXP_SCHEMA_LANGUAGE);
  318. if ( val != null && W3C_XML_SCHEMA.equals(val) ) {
  319. xmlReader.setProperty(name, value);
  320. parserFeatures.put(name, value);
  321. }
  322. else {
  323. throw new SAXNotSupportedException(
  324. SAXMessageFormatter.formatMessage(null,
  325. "jaxp-order-not-supported",
  326. new Object[] {JAXP_SCHEMA_LANGUAGE, JAXP_SCHEMA_SOURCE}));
  327. }
  328. }
  329. /*else if(name.equlas(Constants.ENTITY_EXPANSION_LIMIT)){
  330. String elimit = (String)value;
  331. if(elimit != null && elimit != ""){
  332. int val = Integer.parseInt(elimit);
  333. secureProcessing.setEntityExpansionLimit(val);
  334. }
  335. }else if(name.equals(Constants.MAX_OCCUR_LIMIT)) {
  336. String mlimit = (String)value;
  337. if(mlimit != null && mlimit != ""){
  338. int val = Integer.parseInt(mlimit);
  339. secureProcessing.setMaxOccurNodeLimit(val);
  340. }
  341. }*/
  342. else if(value instanceof Boolean){
  343. //assume feature
  344. xmlReader.setFeature(name,((Boolean)value).booleanValue());
  345. parserFeatures.put(name, value);
  346. }else{
  347. xmlReader.setProperty(name, value);
  348. parserFeatures.put(name, value);
  349. }
  350. }
  351. /**
  352. * returns the particular property requested for in the underlying
  353. * implementation of org.xml.sax.XMLReader.
  354. */
  355. public Object getProperty(String name)
  356. throws SAXNotRecognizedException, SAXNotSupportedException
  357. {
  358. // TODO: reroute those properties to use new JAXP1.3 API. -KK
  359. if (JAXP_SCHEMA_LANGUAGE.equals(name)) {
  360. // JAXP 1.2 support
  361. return schemaLanguage;
  362. } else {
  363. return xmlReader.getProperty(name);
  364. }
  365. }
  366. public Schema getSchema(){
  367. return grammar;
  368. }
  369. /**
  370. * <p>Return True if secure processing in effect.</p>
  371. * Defaults to <code>false</code>.</p>
  372. *
  373. * @return state of Schema Caching
  374. */
  375. public boolean isSecureProcessing(){
  376. return secureProcessing!=null;
  377. }
  378. }