1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
  6. * 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.dom;
  58. import com.sun.org.apache.xerces.internal.impl.RevalidationHandler;
  59. import com.sun.org.apache.xerces.internal.parsers.DOMParserImpl;
  60. import com.sun.org.apache.xerces.internal.util.XMLChar;
  61. import com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl;
  62. import org.w3c.dom.DOMException;
  63. import org.w3c.dom.DOMImplementation;
  64. import org.w3c.dom.Document;
  65. import org.w3c.dom.DocumentType;
  66. import org.w3c.dom.Element;
  67. import org.w3c.dom.ls.LSParser;
  68. import org.w3c.dom.ls.DOMImplementationLS;
  69. import org.w3c.dom.ls.LSInput;
  70. import org.w3c.dom.ls.LSOutput;
  71. import org.w3c.dom.ls.LSSerializer;
  72. /**
  73. * The DOMImplementation class is description of a particular
  74. * implementation of the Document Object Model. As such its data is
  75. * static, shared by all instances of this implementation.
  76. * <P>
  77. * The DOM API requires that it be a real object rather than static
  78. * methods. However, there's nothing that says it can't be a singleton,
  79. * so that's how I've implemented it.
  80. * <P>
  81. * This particular class, along with CoreDocumentImpl, supports the DOM
  82. * Core and Load/Save (Experimental). Optional modules are supported by
  83. * the more complete DOMImplementation class along with DocumentImpl.
  84. * @version $Id: CoreDOMImplementationImpl.java,v 1.30 2004/02/17 07:14:48 neeraj Exp $
  85. * @since PR-DOM-Level-1-19980818.
  86. */
  87. public class CoreDOMImplementationImpl
  88. implements DOMImplementation, DOMImplementationLS {
  89. //
  90. // Data
  91. //
  92. // validators pool
  93. private static final int SIZE = 2;
  94. private RevalidationHandler validators[] = new RevalidationHandler[SIZE];
  95. private int freeValidatorIndex = -1;
  96. private int currentSize = SIZE;
  97. // Document and doctype counter. Used to assign order to documents and
  98. // doctypes without owners, on an demand basis. Used for
  99. // compareDocumentPosition
  100. private int docAndDoctypeCounter = 0;
  101. // static
  102. /** Dom implementation singleton. */
  103. static CoreDOMImplementationImpl singleton =
  104. new CoreDOMImplementationImpl();
  105. //
  106. // Public methods
  107. //
  108. /** NON-DOM: Obtain and return the single shared object */
  109. public static DOMImplementation getDOMImplementation() {
  110. return singleton;
  111. }
  112. //
  113. // DOMImplementation methods
  114. //
  115. /**
  116. * Test if the DOM implementation supports a specific "feature" --
  117. * currently meaning language and level thereof.
  118. *
  119. * @param feature The package name of the feature to test.
  120. * In Level 1, supported values are "HTML" and "XML" (case-insensitive).
  121. * At this writing, com.sun.org.apache.xerces.internal.dom supports only XML.
  122. *
  123. * @param version The version number of the feature being tested.
  124. * This is interpreted as "Version of the DOM API supported for the
  125. * specified Feature", and in Level 1 should be "1.0"
  126. *
  127. * @return true iff this implementation is compatable with the specified
  128. * feature and version.
  129. */
  130. public boolean hasFeature(String feature, String version) {
  131. boolean anyVersion = version == null || version.length() == 0;
  132. if (feature.startsWith("+")) {
  133. feature = feature.substring(1);
  134. }
  135. // check if Xalan implementation is around and if yes report true for supporting
  136. // XPath API
  137. if ((feature.equalsIgnoreCase("XPath")
  138. || feature.equalsIgnoreCase("+XPath"))
  139. && (anyVersion || version.equals("3.0"))) {
  140. try {
  141. Class xpathClass =
  142. ObjectFactory.findProviderClass(
  143. "com.sun.org.apache.xpath.internal.domapi.XPathEvaluatorImpl",
  144. ObjectFactory.findClassLoader(),
  145. true);
  146. } catch (Exception e) {
  147. return false;
  148. }
  149. return true;
  150. }
  151. return (
  152. feature.equalsIgnoreCase("Core")
  153. && (anyVersion
  154. || version.equals("1.0")
  155. || version.equals("2.0")
  156. || version.equals("3.0")))
  157. || (feature.equalsIgnoreCase("XML")
  158. && (anyVersion
  159. || version.equals("1.0")
  160. || version.equals("2.0")
  161. || version.equals("3.0")))
  162. || (feature.equalsIgnoreCase("LS")
  163. && (anyVersion || version.equals("3.0")));
  164. } // hasFeature(String,String):boolean
  165. /**
  166. * Introduced in DOM Level 2. <p>
  167. *
  168. * Creates an empty DocumentType node.
  169. *
  170. * @param qualifiedName The qualified name of the document type to be created.
  171. * @param publicID The document type public identifier.
  172. * @param systemID The document type system identifier.
  173. * @since WD-DOM-Level-2-19990923
  174. */
  175. public DocumentType createDocumentType( String qualifiedName,
  176. String publicID, String systemID) {
  177. // REVISIT: this might allow creation of invalid name for DOCTYPE
  178. // xmlns prefix.
  179. // also there is no way for a user to turn off error checking.
  180. checkQName(qualifiedName);
  181. return new DocumentTypeImpl(null, qualifiedName, publicID, systemID);
  182. }
  183. final void checkQName(String qname){
  184. int index = qname.indexOf(':');
  185. int lastIndex = qname.lastIndexOf(':');
  186. int length = qname.length();
  187. // it is an error for NCName to have more than one ':'
  188. // check if it is valid QName [Namespace in XML production 6]
  189. if (index == 0 || index == length - 1 || lastIndex != index) {
  190. String msg =
  191. DOMMessageFormatter.formatMessage(
  192. DOMMessageFormatter.DOM_DOMAIN,
  193. "NAMESPACE_ERR",
  194. null);
  195. throw new DOMException(DOMException.NAMESPACE_ERR, msg);
  196. }
  197. int start = 0;
  198. // Namespace in XML production [6]
  199. if (index > 0) {
  200. // check that prefix is NCName
  201. if (!XMLChar.isNCNameStart(qname.charAt(start))) {
  202. String msg =
  203. DOMMessageFormatter.formatMessage(
  204. DOMMessageFormatter.DOM_DOMAIN,
  205. "INVALID_CHARACTER_ERR",
  206. null);
  207. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  208. }
  209. for (int i = 1; i < index; i++) {
  210. if (!XMLChar.isNCName(qname.charAt(i))) {
  211. String msg =
  212. DOMMessageFormatter.formatMessage(
  213. DOMMessageFormatter.DOM_DOMAIN,
  214. "INVALID_CHARACTER_ERR",
  215. null);
  216. throw new DOMException(
  217. DOMException.INVALID_CHARACTER_ERR,
  218. msg);
  219. }
  220. }
  221. start = index + 1;
  222. }
  223. // check local part
  224. if (!XMLChar.isNCNameStart(qname.charAt(start))) {
  225. // REVISIT: add qname parameter to the message
  226. String msg =
  227. DOMMessageFormatter.formatMessage(
  228. DOMMessageFormatter.DOM_DOMAIN,
  229. "INVALID_CHARACTER_ERR",
  230. null);
  231. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  232. }
  233. for (int i = start + 1; i < length; i++) {
  234. if (!XMLChar.isNCName(qname.charAt(i))) {
  235. String msg =
  236. DOMMessageFormatter.formatMessage(
  237. DOMMessageFormatter.DOM_DOMAIN,
  238. "INVALID_CHARACTER_ERR",
  239. null);
  240. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  241. }
  242. }
  243. }
  244. /**
  245. * Introduced in DOM Level 2. <p>
  246. *
  247. * Creates an XML Document object of the specified type with its document
  248. * element.
  249. *
  250. * @param namespaceURI The namespace URI of the document
  251. * element to create, or null.
  252. * @param qualifiedName The qualified name of the document
  253. * element to create.
  254. * @param doctype The type of document to be created or null.<p>
  255. *
  256. * When doctype is not null, its
  257. * Node.ownerDocument attribute is set to
  258. * the document being created.
  259. * @return Document A new Document object.
  260. * @throws DOMException WRONG_DOCUMENT_ERR: Raised if doctype has
  261. * already been used with a different document.
  262. * @since WD-DOM-Level-2-19990923
  263. */
  264. public Document createDocument(
  265. String namespaceURI,
  266. String qualifiedName,
  267. DocumentType doctype)
  268. throws DOMException {
  269. if (doctype != null && doctype.getOwnerDocument() != null) {
  270. String msg =
  271. DOMMessageFormatter.formatMessage(
  272. DOMMessageFormatter.DOM_DOMAIN,
  273. "WRONG_DOCUMENT_ERR",
  274. null);
  275. throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
  276. }
  277. CoreDocumentImpl doc = new CoreDocumentImpl(doctype);
  278. Element e = doc.createElementNS(namespaceURI, qualifiedName);
  279. doc.appendChild(e);
  280. return doc;
  281. }
  282. /**
  283. * DOM Level 3 WD - Experimental.
  284. */
  285. public Object getFeature(String feature, String version) {
  286. if (singleton.hasFeature(feature, version)){
  287. return singleton;
  288. }
  289. return null;
  290. }
  291. // DOM L3 LS
  292. /**
  293. * DOM Level 3 LS CR - Experimental.
  294. * Create a new <code>LSParser</code>. The newly constructed parser may
  295. * then be configured by means of its <code>DOMConfiguration</code>
  296. * object, and used to parse documents by means of its <code>parse</code>
  297. * method.
  298. * @param mode The <code>mode</code> argument is either
  299. * <code>MODE_SYNCHRONOUS</code> or <code>MODE_ASYNCHRONOUS</code>, if
  300. * <code>mode</code> is <code>MODE_SYNCHRONOUS</code> then the
  301. * <code>LSParser</code> that is created will operate in synchronous
  302. * mode, if it's <code>MODE_ASYNCHRONOUS</code> then the
  303. * <code>LSParser</code> that is created will operate in asynchronous
  304. * mode.
  305. * @param schemaType An absolute URI representing the type of the schema
  306. * language used during the load of a <code>Document</code> using the
  307. * newly created <code>LSParser</code>. Note that no lexical checking
  308. * is done on the absolute URI. In order to create a
  309. * <code>LSParser</code> for any kind of schema types (i.e. the
  310. * LSParser will be free to use any schema found), use the value
  311. * <code>null</code>.
  312. * <p ><b>Note:</b> For W3C XML Schema [<a href='http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/'>XML Schema Part 1</a>]
  313. * , applications must use the value
  314. * <code>"http://www.w3.org/2001/XMLSchema"</code>. For XML DTD [<a href='http://www.w3.org/TR/2000/REC-xml-20001006'>XML 1.0</a>],
  315. * applications must use the value
  316. * <code>"http://www.w3.org/TR/REC-xml"</code>. Other Schema languages
  317. * are outside the scope of the W3C and therefore should recommend an
  318. * absolute URI in order to use this method.
  319. * @return The newly created <code>LSParser</code> object. This
  320. * <code>LSParser</code> is either synchronous or asynchronous
  321. * depending on the value of the <code>mode</code> argument.
  322. * <p ><b>Note:</b> By default, the newly created <code>LSParser</code>
  323. * does not contain a <code>DOMErrorHandler</code>, i.e. the value of
  324. * the "<a href='http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030609/core.html#parameter-error-handler'>
  325. * error-handler</a>" configuration parameter is <code>null</code>. However, implementations
  326. * may provide a default error handler at creation time. In that case,
  327. * the initial value of the <code>"error-handler"</code> configuration
  328. * parameter on the new created <code>LSParser</code> contains a
  329. * reference to the default error handler.
  330. * @exception DOMException
  331. * NOT_SUPPORTED_ERR: Raised if the requested mode or schema type is
  332. * not supported.
  333. */
  334. public LSParser createLSParser(short mode, String schemaType)
  335. throws DOMException {
  336. if (mode != DOMImplementationLS.MODE_SYNCHRONOUS || (schemaType !=null &&
  337. !"http://www.w3.org/2001/XMLSchema".equals(schemaType) &&
  338. !"http://www.w3.org/TR/REC-xml".equals(schemaType))) {
  339. String msg =
  340. DOMMessageFormatter.formatMessage(
  341. DOMMessageFormatter.DOM_DOMAIN,
  342. "NOT_SUPPORTED_ERR",
  343. null);
  344. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
  345. }
  346. if (schemaType != null
  347. && schemaType.equals("http://www.w3.org/TR/REC-xml")) {
  348. return new DOMParserImpl(
  349. "com.sun.org.apache.xerces.internal.parsers.XML11Configuration",
  350. schemaType);
  351. }
  352. else {
  353. // create default parser configuration validating against XMLSchemas
  354. return new DOMParserImpl(
  355. "com.sun.org.apache.xerces.internal.parsers.XML11Configuration",
  356. schemaType);
  357. }
  358. }
  359. /**
  360. * DOM Level 3 LS CR - Experimental.
  361. * Create a new <code>LSSerializer</code> object.
  362. * @return The newly created <code>LSSerializer</code> object.
  363. * <p ><b>Note:</b> By default, the newly created
  364. * <code>LSSerializer</code> has no <code>DOMErrorHandler</code>,
  365. * i.e. the value of the <code>"error-handler"</code> configuration
  366. * parameter is <code>null</code>. However, implementations may
  367. * provide a default error handler at creation time. In that case, the
  368. * initial value of the <code>"error-handler"</code> configuration
  369. * parameter on the new created <code>LSSerializer</code> contains a
  370. * reference to the default error handler.
  371. */
  372. public LSSerializer createLSSerializer() {
  373. return new DOMSerializerImpl();
  374. }
  375. /**
  376. * DOM Level 3 LS CR - Experimental.
  377. * Create a new empty input source.
  378. * @return The newly created input object.
  379. */
  380. public LSInput createLSInput() {
  381. return new DOMInputImpl();
  382. }
  383. synchronized Object getDTDValidator() {
  384. return ObjectFactory.newInstance( "com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator", ObjectFactory.findClassLoader(), true);
  385. }
  386. //
  387. // Protected methods
  388. //
  389. /** NON-DOM: retrieve validator. */
  390. synchronized RevalidationHandler getValidator(String schemaType) {
  391. // REVISIT: implement retrieving DTD validator
  392. if (freeValidatorIndex < 0) {
  393. // create new validator - we should not attempt
  394. // to restrict the number of validation handlers being
  395. // requested
  396. return (RevalidationHandler) (ObjectFactory .newInstance( "com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator", ObjectFactory.findClassLoader(), true));
  397. }
  398. // return first available validator
  399. RevalidationHandler val = validators[freeValidatorIndex];
  400. validators[freeValidatorIndex--] = null;
  401. return val;
  402. }
  403. /** NON-DOM: release validator */
  404. synchronized void releaseValidator(String schemaType,
  405. RevalidationHandler validator) {
  406. // REVISIT: implement support for DTD validators as well
  407. ++freeValidatorIndex;
  408. if (validators.length == freeValidatorIndex ){
  409. // resize size of the validators
  410. currentSize+=SIZE;
  411. RevalidationHandler newarray[] = new RevalidationHandler[currentSize];
  412. System.arraycopy(validators, 0, newarray, 0, validators.length);
  413. validators = newarray;
  414. }
  415. validators[freeValidatorIndex]=validator;
  416. }
  417. /** NON-DOM: increment document/doctype counter */
  418. protected synchronized int assignDocumentNumber() {
  419. return ++docAndDoctypeCounter;
  420. }
  421. /** NON-DOM: increment document/doctype counter */
  422. protected synchronized int assignDocTypeNumber() {
  423. return ++docAndDoctypeCounter;
  424. }
  425. /* DOM Level 3 LS CR - Experimental.
  426. *
  427. * Create a new empty output destination object where
  428. * <code>LSOutput.characterStream</code>,
  429. * <code>LSOutput.byteStream</code>, <code>LSOutput.systemId</code>,
  430. * <code>LSOutput.encoding</code> are null.
  431. * @return The newly created output object.
  432. */
  433. public LSOutput createLSOutput() {
  434. return new DOMOutputImpl();
  435. }
  436. } // class DOMImplementationImpl