1. /*
  2. * Copyright 2001-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: MultiDOM.java,v 1.31 2004/02/16 22:54:59 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.dom;
  20. import com.sun.org.apache.xalan.internal.xsltc.DOM;
  21. import com.sun.org.apache.xalan.internal.xsltc.StripFilter;
  22. import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
  23. import com.sun.org.apache.xalan.internal.xsltc.TransletException;
  24. import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
  25. import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;
  26. import com.sun.org.apache.xml.internal.dtm.DTM;
  27. import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  28. import com.sun.org.apache.xml.internal.dtm.DTMManager;
  29. import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase;
  30. import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
  31. import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector;
  32. import org.w3c.dom.Node;
  33. import org.w3c.dom.NodeList;
  34. /**
  35. * @author Jacek Ambroziak
  36. * @author Morten Jorgensen
  37. * @author Erwin Bolwidt <ejb@klomp.org>
  38. */
  39. public final class MultiDOM implements DOM {
  40. private static final int NO_TYPE = DOM.FIRST_TYPE - 2;
  41. private static final int INITIAL_SIZE = 4;
  42. private DOM[] _adapters;
  43. private DOMAdapter _main;
  44. private DTMManager _dtmManager;
  45. private int _free;
  46. private int _size;
  47. private Hashtable _documents = new Hashtable();
  48. private final class AxisIterator extends DTMAxisIteratorBase {
  49. // constitutive data
  50. private final int _axis;
  51. private final int _type;
  52. // implementation mechanism
  53. private DTMAxisIterator _source;
  54. private int _dtmId = -1;
  55. public AxisIterator(final int axis, final int type) {
  56. _axis = axis;
  57. _type = type;
  58. }
  59. public int next() {
  60. if (_source == null) {
  61. return(END);
  62. }
  63. return _source.next();
  64. }
  65. public void setRestartable(boolean flag) {
  66. if (_source != null) {
  67. _source.setRestartable(flag);
  68. }
  69. }
  70. public DTMAxisIterator setStartNode(final int node) {
  71. if (node == DTM.NULL) {
  72. return this;
  73. }
  74. int dom = node >>> DTMManager.IDENT_DTM_NODE_BITS;
  75. // Get a new source first time and when mask changes
  76. if (_source == null || _dtmId != dom) {
  77. if (_type == NO_TYPE) {
  78. _source = _adapters[dom].getAxisIterator(_axis);
  79. } else if (_axis == Axis.CHILD) {
  80. _source = _adapters[dom].getTypedChildren(_type);
  81. } else {
  82. _source = _adapters[dom].getTypedAxisIterator(_axis, _type);
  83. }
  84. }
  85. _dtmId = dom;
  86. _source.setStartNode(node);
  87. return this;
  88. }
  89. public DTMAxisIterator reset() {
  90. if (_source != null) {
  91. _source.reset();
  92. }
  93. return this;
  94. }
  95. public int getLast() {
  96. if (_source != null) {
  97. return _source.getLast();
  98. }
  99. else {
  100. return END;
  101. }
  102. }
  103. public int getPosition() {
  104. if (_source != null) {
  105. return _source.getPosition();
  106. }
  107. else {
  108. return END;
  109. }
  110. }
  111. public boolean isReverse() {
  112. return Axis.isReverse[_axis];
  113. }
  114. public void setMark() {
  115. if (_source != null) {
  116. _source.setMark();
  117. }
  118. }
  119. public void gotoMark() {
  120. if (_source != null) {
  121. _source.gotoMark();
  122. }
  123. }
  124. public DTMAxisIterator cloneIterator() {
  125. final AxisIterator clone = new AxisIterator(_axis, _type);
  126. if (_source != null) {
  127. clone._source = _source.cloneIterator();
  128. }
  129. clone._dtmId = _dtmId;
  130. return clone;
  131. }
  132. } // end of AxisIterator
  133. /**************************************************************
  134. * This is a specialised iterator for predicates comparing node or
  135. * attribute values to variable or parameter values.
  136. */
  137. private final class NodeValueIterator extends DTMAxisIteratorBase {
  138. private DTMAxisIterator _source;
  139. private String _value;
  140. private boolean _op;
  141. private final boolean _isReverse;
  142. private int _returnType = RETURN_PARENT;
  143. public NodeValueIterator(DTMAxisIterator source, int returnType,
  144. String value, boolean op) {
  145. _source = source;
  146. _returnType = returnType;
  147. _value = value;
  148. _op = op;
  149. _isReverse = source.isReverse();
  150. }
  151. public boolean isReverse() {
  152. return _isReverse;
  153. }
  154. public DTMAxisIterator cloneIterator() {
  155. try {
  156. NodeValueIterator clone = (NodeValueIterator)super.clone();
  157. clone._source = _source.cloneIterator();
  158. clone.setRestartable(false);
  159. return clone.reset();
  160. }
  161. catch (CloneNotSupportedException e) {
  162. BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
  163. e.toString());
  164. return null;
  165. }
  166. }
  167. public void setRestartable(boolean isRestartable) {
  168. _isRestartable = isRestartable;
  169. _source.setRestartable(isRestartable);
  170. }
  171. public DTMAxisIterator reset() {
  172. _source.reset();
  173. return resetPosition();
  174. }
  175. public int next() {
  176. int node;
  177. while ((node = _source.next()) != END) {
  178. String val = getStringValueX(node);
  179. if (_value.equals(val) == _op) {
  180. if (_returnType == RETURN_CURRENT)
  181. return returnNode(node);
  182. else
  183. return returnNode(getParent(node));
  184. }
  185. }
  186. return END;
  187. }
  188. public DTMAxisIterator setStartNode(int node) {
  189. if (_isRestartable) {
  190. _source.setStartNode(_startNode = node);
  191. return resetPosition();
  192. }
  193. return this;
  194. }
  195. public void setMark() {
  196. _source.setMark();
  197. }
  198. public void gotoMark() {
  199. _source.gotoMark();
  200. }
  201. }
  202. public MultiDOM(DOM main) {
  203. _size = INITIAL_SIZE;
  204. _free = 1;
  205. _adapters = new DOM[INITIAL_SIZE];
  206. DOMAdapter adapter = (DOMAdapter)main;
  207. _adapters[0] = adapter;
  208. _main = adapter;
  209. DOM dom = adapter.getDOMImpl();
  210. if (dom instanceof DTMDefaultBase) {
  211. _dtmManager = ((DTMDefaultBase)dom).getManager();
  212. }
  213. // %HZ% %REVISIT% Is this the right thing to do here? In the old
  214. // %HZ% %REVISIT% version, the main document did not get added through
  215. // %HZ% %REVISIT% a call to addDOMAdapter, which meant it couldn't be
  216. // %HZ% %REVISIT% found by a call to getDocumentMask. The problem is
  217. // %HZ% %REVISIT% TransformerHandler is typically constructed with a
  218. // %HZ% %REVISIT% system ID equal to the stylesheet's URI; with SAX
  219. // %HZ% %REVISIT% input, it ends up giving that URI to the document.
  220. // %HZ% %REVISIT% Then, any references to document('') are resolved
  221. // %HZ% %REVISIT% using the stylesheet's URI.
  222. // %HZ% %REVISIT% MultiDOM.getDocumentMask is called to verify that
  223. // %HZ% %REVISIT% a document associated with that URI has not been
  224. // %HZ% %REVISIT% encountered, and that method ends up returning the
  225. // %HZ% %REVISIT% mask of the main document, when what we really what
  226. // %HZ% %REVISIT% is to read the stylesheet itself!
  227. addDOMAdapter(adapter, false);
  228. }
  229. public int nextMask() {
  230. return _free;
  231. }
  232. public void setupMapping(String[] names, String[] uris, int[] types, String[] namespaces) {
  233. // This method only has a function in DOM adapters
  234. }
  235. public int addDOMAdapter(DOMAdapter adapter) {
  236. return addDOMAdapter(adapter, true);
  237. }
  238. private int addDOMAdapter(DOMAdapter adapter, boolean indexByURI) {
  239. // Add the DOM adapter to the array of DOMs
  240. DOM dom = adapter.getDOMImpl();
  241. int domNo = 1;
  242. int dtmSize = 1;
  243. SuballocatedIntVector dtmIds = null;
  244. if (dom instanceof DTMDefaultBase) {
  245. DTMDefaultBase dtmdb = (DTMDefaultBase)dom;
  246. dtmIds = dtmdb.getDTMIDs();
  247. dtmSize = dtmIds.size();
  248. domNo = dtmIds.elementAt(dtmSize-1) >>> DTMManager.IDENT_DTM_NODE_BITS;
  249. }
  250. else if (dom instanceof SimpleResultTreeImpl) {
  251. SimpleResultTreeImpl simpleRTF = (SimpleResultTreeImpl)dom;
  252. domNo = simpleRTF.getDocument() >>> DTMManager.IDENT_DTM_NODE_BITS;
  253. }
  254. if (domNo >= _size) {
  255. int oldSize = _size;
  256. do {
  257. _size *= 2;
  258. } while (_size <= domNo);
  259. final DOMAdapter[] newArray = new DOMAdapter[_size];
  260. System.arraycopy(_adapters, 0, newArray, 0, oldSize);
  261. _adapters = newArray;
  262. }
  263. _free = domNo + 1;
  264. if (dtmSize == 1) {
  265. _adapters[domNo] = adapter;
  266. }
  267. else if (dtmIds != null) {
  268. int domPos = 0;
  269. for (int i = dtmSize - 1; i >= 0; i--) {
  270. domPos = dtmIds.elementAt(i) >>> DTMManager.IDENT_DTM_NODE_BITS;
  271. _adapters[domPos] = adapter;
  272. }
  273. domNo = domPos;
  274. }
  275. // Store reference to document (URI) in hashtable
  276. if (indexByURI) {
  277. String uri = adapter.getDocumentURI(0);
  278. _documents.put(uri, new Integer(domNo));
  279. }
  280. // If the dom is an AdaptiveResultTreeImpl, we need to create a
  281. // DOMAdapter around its nested dom object (if it is non-null) and
  282. // add the DOMAdapter to the list.
  283. if (dom instanceof AdaptiveResultTreeImpl) {
  284. AdaptiveResultTreeImpl adaptiveRTF = (AdaptiveResultTreeImpl)dom;
  285. DOM nestedDom = adaptiveRTF.getNestedDOM();
  286. if (nestedDom != null) {
  287. DOMAdapter newAdapter = new DOMAdapter(nestedDom,
  288. adapter.getNamesArray(),
  289. adapter.getUrisArray(),
  290. adapter.getTypesArray(),
  291. adapter.getNamespaceArray());
  292. addDOMAdapter(newAdapter);
  293. }
  294. }
  295. return domNo;
  296. }
  297. public int getDocumentMask(String uri) {
  298. Integer domIdx = (Integer)_documents.get(uri);
  299. if (domIdx == null) {
  300. return(-1);
  301. } else {
  302. return domIdx.intValue();
  303. }
  304. }
  305. public DOM getDOMAdapter(String uri) {
  306. Integer domIdx = (Integer)_documents.get(uri);
  307. if (domIdx == null) {
  308. return(null);
  309. } else {
  310. return(_adapters[domIdx.intValue()]);
  311. }
  312. }
  313. public int getDocument()
  314. {
  315. return _main.getDocument();
  316. }
  317. public DTMManager getDTMManager() {
  318. return _dtmManager;
  319. }
  320. /**
  321. * Returns singleton iterator containing the document root
  322. */
  323. public DTMAxisIterator getIterator() {
  324. // main source document @ 0
  325. return _main.getIterator();
  326. }
  327. public String getStringValue() {
  328. return _main.getStringValue();
  329. }
  330. public DTMAxisIterator getChildren(final int node) {
  331. return _adapters[getDTMId(node)].getChildren(node);
  332. }
  333. public DTMAxisIterator getTypedChildren(final int type) {
  334. return new AxisIterator(Axis.CHILD, type);
  335. }
  336. public DTMAxisIterator getAxisIterator(final int axis) {
  337. return new AxisIterator(axis, NO_TYPE);
  338. }
  339. public DTMAxisIterator getTypedAxisIterator(final int axis, final int type)
  340. {
  341. return new AxisIterator(axis, type);
  342. }
  343. public DTMAxisIterator getNthDescendant(int node, int n,
  344. boolean includeself)
  345. {
  346. return _adapters[getDTMId(node)].getNthDescendant(node, n, includeself);
  347. }
  348. public DTMAxisIterator getNodeValueIterator(DTMAxisIterator iterator,
  349. int type, String value,
  350. boolean op)
  351. {
  352. return(new NodeValueIterator(iterator, type, value, op));
  353. }
  354. public DTMAxisIterator getNamespaceAxisIterator(final int axis,
  355. final int ns)
  356. {
  357. DTMAxisIterator iterator = _main.getNamespaceAxisIterator(axis, ns);
  358. return(iterator);
  359. }
  360. public DTMAxisIterator orderNodes(DTMAxisIterator source, int node) {
  361. return _adapters[getDTMId(node)].orderNodes(source, node);
  362. }
  363. public int getExpandedTypeID(final int node) {
  364. if (node != DTM.NULL) {
  365. return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getExpandedTypeID(node);
  366. }
  367. else {
  368. return DTM.NULL;
  369. }
  370. }
  371. public int getNamespaceType(final int node) {
  372. return _adapters[getDTMId(node)].getNamespaceType(node);
  373. }
  374. public int getNSType(int node)
  375. {
  376. return _adapters[getDTMId(node)].getNSType(node);
  377. }
  378. public int getParent(final int node) {
  379. if (node == DTM.NULL) {
  380. return DTM.NULL;
  381. }
  382. return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getParent(node);
  383. }
  384. public int getAttributeNode(final int type, final int el) {
  385. if (el == DTM.NULL) {
  386. return DTM.NULL;
  387. }
  388. return _adapters[el >>> DTMManager.IDENT_DTM_NODE_BITS].getAttributeNode(type, el);
  389. }
  390. public String getNodeName(final int node) {
  391. if (node == DTM.NULL) {
  392. return "";
  393. }
  394. return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeName(node);
  395. }
  396. public String getNodeNameX(final int node) {
  397. if (node == DTM.NULL) {
  398. return "";
  399. }
  400. return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeNameX(node);
  401. }
  402. public String getNamespaceName(final int node) {
  403. if (node == DTM.NULL) {
  404. return "";
  405. }
  406. return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNamespaceName(node);
  407. }
  408. public String getStringValueX(final int node) {
  409. if (node == DTM.NULL) {
  410. return "";
  411. }
  412. return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getStringValueX(node);
  413. }
  414. public void copy(final int node, SerializationHandler handler)
  415. throws TransletException
  416. {
  417. if (node != DTM.NULL) {
  418. _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].copy(node, handler);
  419. }
  420. }
  421. public void copy(DTMAxisIterator nodes, SerializationHandler handler)
  422. throws TransletException
  423. {
  424. int node;
  425. while ((node = nodes.next()) != DTM.NULL) {
  426. _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].copy(node, handler);
  427. }
  428. }
  429. public String shallowCopy(final int node, SerializationHandler handler)
  430. throws TransletException
  431. {
  432. if (node == DTM.NULL) {
  433. return "";
  434. }
  435. return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].shallowCopy(node, handler);
  436. }
  437. public boolean lessThan(final int node1, final int node2) {
  438. if (node1 == DTM.NULL) {
  439. return true;
  440. }
  441. if (node2 == DTM.NULL) {
  442. return false;
  443. }
  444. final int dom1 = getDTMId(node1);
  445. final int dom2 = getDTMId(node2);
  446. return dom1 == dom2 ? _adapters[dom1].lessThan(node1, node2)
  447. : dom1 < dom2;
  448. }
  449. public void characters(final int textNode, SerializationHandler handler)
  450. throws TransletException
  451. {
  452. if (textNode != DTM.NULL) {
  453. _adapters[textNode >>> DTMManager.IDENT_DTM_NODE_BITS].characters(textNode, handler);
  454. }
  455. }
  456. public void setFilter(StripFilter filter) {
  457. for (int dom=0; dom<_free; dom++) {
  458. if (_adapters[dom] != null) {
  459. _adapters[dom].setFilter(filter);
  460. }
  461. }
  462. }
  463. public Node makeNode(int index) {
  464. if (index == DTM.NULL) {
  465. return null;
  466. }
  467. return _adapters[getDTMId(index)].makeNode(index);
  468. }
  469. public Node makeNode(DTMAxisIterator iter) {
  470. // TODO: gather nodes from all DOMs ?
  471. return _main.makeNode(iter);
  472. }
  473. public NodeList makeNodeList(int index) {
  474. if (index == DTM.NULL) {
  475. return null;
  476. }
  477. return _adapters[getDTMId(index)].makeNodeList(index);
  478. }
  479. public NodeList makeNodeList(DTMAxisIterator iter) {
  480. // TODO: gather nodes from all DOMs ?
  481. return _main.makeNodeList(iter);
  482. }
  483. public String getLanguage(int node) {
  484. return _adapters[getDTMId(node)].getLanguage(node);
  485. }
  486. public int getSize() {
  487. int size = 0;
  488. for (int i=0; i<_size; i++) {
  489. size += _adapters[i].getSize();
  490. }
  491. return(size);
  492. }
  493. public String getDocumentURI(int node) {
  494. if (node == DTM.NULL) {
  495. node = DOM.NULL;
  496. }
  497. return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getDocumentURI(0);
  498. }
  499. public boolean isElement(final int node) {
  500. if (node == DTM.NULL) {
  501. return false;
  502. }
  503. return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isElement(node));
  504. }
  505. public boolean isAttribute(final int node) {
  506. if (node == DTM.NULL) {
  507. return false;
  508. }
  509. return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isAttribute(node));
  510. }
  511. public int getDTMId(int nodeHandle)
  512. {
  513. if (nodeHandle == DTM.NULL)
  514. return 0;
  515. int id = nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS;
  516. while (id >= 2 && _adapters[id] == _adapters[id-1]) {
  517. id--;
  518. }
  519. return id;
  520. }
  521. public int getNodeIdent(int nodeHandle)
  522. {
  523. return _adapters[nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeIdent(nodeHandle);
  524. }
  525. public int getNodeHandle(int nodeId)
  526. {
  527. return _main.getNodeHandle(nodeId);
  528. }
  529. public DOM getResultTreeFrag(int initSize, int rtfType)
  530. {
  531. return _main.getResultTreeFrag(initSize, rtfType);
  532. }
  533. public DOM getResultTreeFrag(int initSize, int rtfType, boolean addToManager)
  534. {
  535. return _main.getResultTreeFrag(initSize, rtfType, addToManager);
  536. }
  537. public DOM getMain()
  538. {
  539. return _main;
  540. }
  541. /**
  542. * Returns a DOMBuilder class wrapped in a SAX adapter.
  543. */
  544. public SerializationHandler getOutputDomBuilder()
  545. {
  546. return _main.getOutputDomBuilder();
  547. }
  548. public String lookupNamespace(int node, String prefix)
  549. throws TransletException
  550. {
  551. return _main.lookupNamespace(node, prefix);
  552. }
  553. // %HZ% Does this method make any sense here???
  554. public String getUnparsedEntityURI(String entity) {
  555. return _main.getUnparsedEntityURI(entity);
  556. }
  557. // %HZ% Does this method make any sense here???
  558. public Hashtable getElementsWithIDs() {
  559. return _main.getElementsWithIDs();
  560. }
  561. }