1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: XSLTCDTMManager.java,v 1.6 2004/02/23 10:29:36 aruny Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.dom;
  20. import javax.xml.transform.Source;
  21. import javax.xml.transform.dom.DOMSource;
  22. import javax.xml.transform.sax.SAXSource;
  23. import javax.xml.transform.stream.StreamSource;
  24. import com.sun.org.apache.xml.internal.dtm.DTM;
  25. import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
  26. import com.sun.org.apache.xml.internal.dtm.DTMException;
  27. import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
  28. import com.sun.org.apache.xml.internal.dtm.ref.DTMManagerDefault;
  29. import com.sun.org.apache.xml.internal.res.XMLErrorResources;
  30. import com.sun.org.apache.xml.internal.res.XMLMessages;
  31. import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
  32. import com.sun.org.apache.xalan.internal.xsltc.trax.DOM2SAX;
  33. import org.xml.sax.InputSource;
  34. import org.xml.sax.SAXNotRecognizedException;
  35. import org.xml.sax.SAXNotSupportedException;
  36. import org.xml.sax.XMLReader;
  37. /**
  38. * The default implementation for the DTMManager.
  39. */
  40. public class XSLTCDTMManager extends DTMManagerDefault
  41. {
  42. /** The default class name to use as the manager. */
  43. private static final String DEFAULT_CLASS_NAME =
  44. "com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager";
  45. private static final String DEFAULT_PROP_NAME =
  46. "com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager";
  47. /** Set this to true if you want a dump of the DTM after creation */
  48. private static final boolean DUMPTREE = false;
  49. /** Set this to true if you want basic diagnostics */
  50. private static final boolean DEBUG = false;
  51. /**
  52. * Constructor DTMManagerDefault
  53. *
  54. */
  55. public XSLTCDTMManager()
  56. {
  57. super();
  58. }
  59. /**
  60. * Obtain a new instance of a <code>DTMManager</code>.
  61. * This static method creates a new factory instance.
  62. * The current implementation just returns a new XSLTCDTMManager instance.
  63. */
  64. public static XSLTCDTMManager newInstance()
  65. {
  66. return new XSLTCDTMManager();
  67. }
  68. /**
  69. * Look up the class that provides the XSLTC DTM Manager service.
  70. * The following lookup procedure is used to find the service provider.
  71. * <ol>
  72. * <li>The value of the
  73. * <code>com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager</code> property, is
  74. * checked.</li>
  75. * <li>The <code>xalan.propeties</code> file is checked for a property
  76. * of the same name.</li>
  77. * <li>The
  78. * <code>META-INF/services/com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager</code>
  79. * file is checked.
  80. * </ol>
  81. * The default is <code>com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager</code>.
  82. */
  83. public static Class getDTMManagerClass() {
  84. Class mgrClass = ObjectFactory.lookUpFactoryClass(DEFAULT_PROP_NAME,
  85. null,
  86. DEFAULT_CLASS_NAME);
  87. // If no class found, default to this one. (This should never happen -
  88. // the ObjectFactory has already been told that the current class is
  89. // the default).
  90. return (mgrClass != null) ? mgrClass : XSLTCDTMManager.class;
  91. }
  92. /**
  93. * Get an instance of a DTM, loaded with the content from the
  94. * specified source. If the unique flag is true, a new instance will
  95. * always be returned. Otherwise it is up to the DTMManager to return a
  96. * new instance or an instance that it already created and may be being used
  97. * by someone else.
  98. * (I think more parameters will need to be added for error handling, and
  99. * entity resolution).
  100. *
  101. * @param source the specification of the source object.
  102. * @param unique true if the returned DTM must be unique, probably because it
  103. * is going to be mutated.
  104. * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
  105. * be null.
  106. * @param incremental true if the DTM should be built incrementally, if
  107. * possible.
  108. * @param doIndexing true if the caller considers it worth it to use
  109. * indexing schemes.
  110. *
  111. * @return a non-null DTM reference.
  112. */
  113. public DTM getDTM(Source source, boolean unique,
  114. DTMWSFilter whiteSpaceFilter, boolean incremental,
  115. boolean doIndexing)
  116. {
  117. return getDTM(source, unique, whiteSpaceFilter, incremental,
  118. doIndexing, false, 0, true, false);
  119. }
  120. /**
  121. * Get an instance of a DTM, loaded with the content from the
  122. * specified source. If the unique flag is true, a new instance will
  123. * always be returned. Otherwise it is up to the DTMManager to return a
  124. * new instance or an instance that it already created and may be being used
  125. * by someone else.
  126. * (I think more parameters will need to be added for error handling, and
  127. * entity resolution).
  128. *
  129. * @param source the specification of the source object.
  130. * @param unique true if the returned DTM must be unique, probably because it
  131. * is going to be mutated.
  132. * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
  133. * be null.
  134. * @param incremental true if the DTM should be built incrementally, if
  135. * possible.
  136. * @param doIndexing true if the caller considers it worth it to use
  137. * indexing schemes.
  138. * @param buildIdIndex true if the id index table should be built.
  139. *
  140. * @return a non-null DTM reference.
  141. */
  142. public DTM getDTM(Source source, boolean unique,
  143. DTMWSFilter whiteSpaceFilter, boolean incremental,
  144. boolean doIndexing, boolean buildIdIndex)
  145. {
  146. return getDTM(source, unique, whiteSpaceFilter, incremental,
  147. doIndexing, false, 0, buildIdIndex, false);
  148. }
  149. /**
  150. * Get an instance of a DTM, loaded with the content from the
  151. * specified source. If the unique flag is true, a new instance will
  152. * always be returned. Otherwise it is up to the DTMManager to return a
  153. * new instance or an instance that it already created and may be being used
  154. * by someone else.
  155. * (I think more parameters will need to be added for error handling, and
  156. * entity resolution).
  157. *
  158. * @param source the specification of the source object.
  159. * @param unique true if the returned DTM must be unique, probably because it
  160. * is going to be mutated.
  161. * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
  162. * be null.
  163. * @param incremental true if the DTM should be built incrementally, if
  164. * possible.
  165. * @param doIndexing true if the caller considers it worth it to use
  166. * indexing schemes.
  167. * @param buildIdIndex true if the id index table should be built.
  168. * @param newNameTable true if we want to use a separate ExpandedNameTable
  169. * for this DTM.
  170. *
  171. * @return a non-null DTM reference.
  172. */
  173. public DTM getDTM(Source source, boolean unique,
  174. DTMWSFilter whiteSpaceFilter, boolean incremental,
  175. boolean doIndexing, boolean buildIdIndex,
  176. boolean newNameTable)
  177. {
  178. return getDTM(source, unique, whiteSpaceFilter, incremental,
  179. doIndexing, false, 0, buildIdIndex, newNameTable);
  180. }
  181. /**
  182. * Get an instance of a DTM, loaded with the content from the
  183. * specified source. If the unique flag is true, a new instance will
  184. * always be returned. Otherwise it is up to the DTMManager to return a
  185. * new instance or an instance that it already created and may be being used
  186. * by someone else.
  187. * (I think more parameters will need to be added for error handling, and
  188. * entity resolution).
  189. *
  190. * @param source the specification of the source object.
  191. * @param unique true if the returned DTM must be unique, probably because it
  192. * is going to be mutated.
  193. * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
  194. * be null.
  195. * @param incremental true if the DTM should be built incrementally, if
  196. * possible.
  197. * @param doIndexing true if the caller considers it worth it to use
  198. * indexing schemes.
  199. * @param hasUserReader true if <code>source</code> is a
  200. * <code>SAXSource</code> object that has an
  201. * <code>XMLReader</code>, that was specified by the
  202. * user.
  203. * @param size Specifies initial size of tables that represent the DTM
  204. * @param buildIdIndex true if the id index table should be built.
  205. *
  206. * @return a non-null DTM reference.
  207. */
  208. public DTM getDTM(Source source, boolean unique,
  209. DTMWSFilter whiteSpaceFilter, boolean incremental,
  210. boolean doIndexing, boolean hasUserReader, int size,
  211. boolean buildIdIndex)
  212. {
  213. return getDTM(source, unique, whiteSpaceFilter, incremental,
  214. doIndexing, hasUserReader, size,
  215. buildIdIndex, false);
  216. }
  217. /**
  218. * Get an instance of a DTM, loaded with the content from the
  219. * specified source. If the unique flag is true, a new instance will
  220. * always be returned. Otherwise it is up to the DTMManager to return a
  221. * new instance or an instance that it already created and may be being used
  222. * by someone else.
  223. * (I think more parameters will need to be added for error handling, and
  224. * entity resolution).
  225. *
  226. * @param source the specification of the source object.
  227. * @param unique true if the returned DTM must be unique, probably because it
  228. * is going to be mutated.
  229. * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
  230. * be null.
  231. * @param incremental true if the DTM should be built incrementally, if
  232. * possible.
  233. * @param doIndexing true if the caller considers it worth it to use
  234. * indexing schemes.
  235. * @param hasUserReader true if <code>source</code> is a
  236. * <code>SAXSource</code> object that has an
  237. * <code>XMLReader</code>, that was specified by the
  238. * user.
  239. * @param size Specifies initial size of tables that represent the DTM
  240. * @param buildIdIndex true if the id index table should be built.
  241. * @param newNameTable true if we want to use a separate ExpandedNameTable
  242. * for this DTM.
  243. *
  244. * @return a non-null DTM reference.
  245. */
  246. public DTM getDTM(Source source, boolean unique,
  247. DTMWSFilter whiteSpaceFilter, boolean incremental,
  248. boolean doIndexing, boolean hasUserReader, int size,
  249. boolean buildIdIndex, boolean newNameTable)
  250. {
  251. if(DEBUG && null != source) {
  252. System.out.println("Starting "+
  253. (unique ? "UNIQUE" : "shared")+
  254. " source: "+source.getSystemId());
  255. }
  256. int dtmPos = getFirstFreeDTMID();
  257. int documentID = dtmPos << IDENT_DTM_NODE_BITS;
  258. if ((null != source) && source instanceof DOMSource)
  259. {
  260. final DOMSource domsrc = (DOMSource) source;
  261. final org.w3c.dom.Node node = domsrc.getNode();
  262. final DOM2SAX dom2sax = new DOM2SAX(node);
  263. SAXImpl dtm;
  264. if (size <= 0) {
  265. dtm = new SAXImpl(this, source, documentID,
  266. whiteSpaceFilter, null, doIndexing,
  267. DTMDefaultBase.DEFAULT_BLOCKSIZE,
  268. buildIdIndex, newNameTable);
  269. } else {
  270. dtm = new SAXImpl(this, source, documentID,
  271. whiteSpaceFilter, null, doIndexing,
  272. size, buildIdIndex, newNameTable);
  273. }
  274. dtm.setDocumentURI(source.getSystemId());
  275. addDTM(dtm, dtmPos, 0);
  276. dom2sax.setContentHandler(dtm);
  277. try {
  278. dom2sax.parse();
  279. }
  280. catch (RuntimeException re) {
  281. throw re;
  282. }
  283. catch (Exception e) {
  284. throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
  285. }
  286. return dtm;
  287. }
  288. else
  289. {
  290. boolean isSAXSource = (null != source)
  291. ? (source instanceof SAXSource) : true;
  292. boolean isStreamSource = (null != source)
  293. ? (source instanceof StreamSource) : false;
  294. if (isSAXSource || isStreamSource) {
  295. XMLReader reader;
  296. InputSource xmlSource;
  297. if (null == source) {
  298. xmlSource = null;
  299. reader = null;
  300. hasUserReader = false; // Make sure the user didn't lie
  301. }
  302. else {
  303. reader = getXMLReader(source);
  304. xmlSource = SAXSource.sourceToInputSource(source);
  305. String urlOfSource = xmlSource.getSystemId();
  306. if (null != urlOfSource) {
  307. try {
  308. urlOfSource = SystemIDResolver.getAbsoluteURI(urlOfSource);
  309. }
  310. catch (Exception e) {
  311. // %REVIEW% Is there a better way to send a warning?
  312. System.err.println("Can not absolutize URL: " + urlOfSource);
  313. }
  314. xmlSource.setSystemId(urlOfSource);
  315. }
  316. }
  317. // Create the basic SAX2DTM.
  318. SAXImpl dtm;
  319. if (size <= 0) {
  320. dtm = new SAXImpl(this, source, documentID, whiteSpaceFilter,
  321. null, doIndexing,
  322. DTMDefaultBase.DEFAULT_BLOCKSIZE,
  323. buildIdIndex, newNameTable);
  324. } else {
  325. dtm = new SAXImpl(this, source, documentID, whiteSpaceFilter,
  326. null, doIndexing, size, buildIdIndex, newNameTable);
  327. }
  328. // Go ahead and add the DTM to the lookup table. This needs to be
  329. // done before any parsing occurs. Note offset 0, since we've just
  330. // created a new DTM.
  331. addDTM(dtm, dtmPos, 0);
  332. if (null == reader) {
  333. // Then the user will construct it themselves.
  334. return dtm;
  335. }
  336. reader.setContentHandler(dtm.getBuilder());
  337. if (!hasUserReader || null == reader.getDTDHandler()) {
  338. reader.setDTDHandler(dtm);
  339. }
  340. if(!hasUserReader || null == reader.getErrorHandler()) {
  341. reader.setErrorHandler(dtm);
  342. }
  343. try {
  344. reader.setProperty("http://xml.org/sax/properties/lexical-handler", dtm);
  345. }
  346. catch (SAXNotRecognizedException e){}
  347. catch (SAXNotSupportedException e){}
  348. try {
  349. reader.parse(xmlSource);
  350. }
  351. catch (RuntimeException re) {
  352. throw re;
  353. }
  354. catch (Exception e) {
  355. throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
  356. } finally {
  357. if (!hasUserReader) {
  358. releaseXMLReader(reader);
  359. }
  360. }
  361. if (DUMPTREE) {
  362. System.out.println("Dumping SAX2DOM");
  363. dtm.dumpDTM(System.err);
  364. }
  365. return dtm;
  366. }
  367. else {
  368. // It should have been handled by a derived class or the caller
  369. // made a mistake.
  370. throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NOT_SUPPORTED, new Object[]{source}));
  371. }
  372. }
  373. }
  374. }