1. /*
  2. * Copyright 2002-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: NodeSequence.java,v 1.11 2004/02/17 04:32:08 minchau Exp $
  18. */
  19. package com.sun.org.apache.xpath.internal.axes;
  20. import java.util.Vector;
  21. import com.sun.org.apache.xml.internal.dtm.DTM;
  22. import com.sun.org.apache.xml.internal.dtm.DTMFilter;
  23. import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  24. import com.sun.org.apache.xml.internal.dtm.DTMManager;
  25. import com.sun.org.apache.xml.internal.utils.NodeVector;
  26. import com.sun.org.apache.xpath.internal.NodeSetDTM;
  27. import com.sun.org.apache.xpath.internal.XPathContext;
  28. import com.sun.org.apache.xpath.internal.objects.XObject;
  29. /**
  30. * This class is the dynamic wrapper for a Xalan DTMIterator instance, and
  31. * provides random access capabilities.
  32. */
  33. public class NodeSequence extends XObject
  34. implements DTMIterator, Cloneable, PathComponent
  35. {
  36. /** The index of the last node in the iteration. */
  37. protected int m_last = -1;
  38. /**
  39. * The index of the next node to be fetched. Useful if this
  40. * is a cached iterator, and is being used as random access
  41. * NodeList.
  42. */
  43. protected int m_next = 0;
  44. /**
  45. * If this iterator needs to cache nodes that are fetched, they
  46. * are stored in the Vector in the generic object.
  47. */
  48. protected NodeVector getVector()
  49. {
  50. return (NodeVector)m_obj;
  51. }
  52. /**
  53. * Set the vector where nodes will be stored.
  54. */
  55. protected void SetVector(NodeVector v)
  56. {
  57. m_obj = v;
  58. }
  59. /**
  60. * If this iterator needs to cache nodes that are fetched, they
  61. * are stored here.
  62. */
  63. public boolean hasCache()
  64. {
  65. return (m_obj != null);
  66. }
  67. /**
  68. * The functional iterator that fetches nodes.
  69. */
  70. protected DTMIterator m_iter;
  71. /**
  72. * Set the functional iterator that fetches nodes.
  73. * @param iter The iterator that is to be contained.
  74. */
  75. public final void setIter(DTMIterator iter)
  76. {
  77. m_iter = iter;
  78. }
  79. /**
  80. * Get the functional iterator that fetches nodes.
  81. * @return The contained iterator.
  82. */
  83. public final DTMIterator getContainedIter()
  84. {
  85. return m_iter;
  86. }
  87. /**
  88. * The DTMManager to use if we're using a NodeVector only.
  89. * We may well want to do away with this, and store it in the NodeVector.
  90. */
  91. protected DTMManager m_dtmMgr;
  92. // ==== Constructors ====
  93. /**
  94. * Create a new NodeSequence from a (already cloned) iterator.
  95. *
  96. * @param iter Cloned (not static) DTMIterator.
  97. * @param context The initial context node.
  98. * @param xctxt The execution context.
  99. * @param shouldCacheNodes True if this sequence can random access.
  100. */
  101. public NodeSequence(DTMIterator iter, int context, XPathContext xctxt, boolean shouldCacheNodes)
  102. {
  103. setIter(iter);
  104. setRoot(context, xctxt);
  105. setShouldCacheNodes(shouldCacheNodes);
  106. }
  107. /**
  108. * Create a new NodeSequence from a (already cloned) iterator.
  109. *
  110. * @param iter Cloned (not static) DTMIterator.
  111. */
  112. public NodeSequence(Object nodeVector)
  113. {
  114. super(nodeVector);
  115. if(null != nodeVector)
  116. {
  117. assertion(nodeVector instanceof NodeVector,
  118. "Must have a NodeVector as the object for NodeSequence!");
  119. if(nodeVector instanceof DTMIterator)
  120. {
  121. setIter((DTMIterator)nodeVector);
  122. m_last = ((DTMIterator)nodeVector).getLength();
  123. }
  124. }
  125. }
  126. /**
  127. * Construct an empty XNodeSet object. This is used to create a mutable
  128. * nodeset to which random nodes may be added.
  129. */
  130. public NodeSequence(DTMManager dtmMgr)
  131. {
  132. super(new NodeVector());
  133. m_last = 0;
  134. m_dtmMgr = dtmMgr;
  135. }
  136. /**
  137. * Create a new NodeSequence in an invalid (null) state.
  138. */
  139. public NodeSequence()
  140. {
  141. }
  142. /**
  143. * @see DTMIterator#getDTM(int)
  144. */
  145. public DTM getDTM(int nodeHandle)
  146. {
  147. DTMManager mgr = getDTMManager();
  148. if(null != mgr)
  149. return getDTMManager().getDTM(nodeHandle);
  150. else
  151. {
  152. assertion(false, "Can not get a DTM Unless a DTMManager has been set!");
  153. return null;
  154. }
  155. }
  156. /**
  157. * @see DTMIterator#getDTMManager()
  158. */
  159. public DTMManager getDTMManager()
  160. {
  161. return m_dtmMgr;
  162. }
  163. /**
  164. * @see DTMIterator#getRoot()
  165. */
  166. public int getRoot()
  167. {
  168. if(null != m_iter)
  169. return m_iter.getRoot();
  170. else
  171. {
  172. // NodeSetDTM will call this, and so it's not a good thing to throw
  173. // an assertion here.
  174. // assertion(false, "Can not get the root from a non-iterated NodeSequence!");
  175. return DTM.NULL;
  176. }
  177. }
  178. /**
  179. * @see DTMIterator#setRoot(int, Object)
  180. */
  181. public void setRoot(int nodeHandle, Object environment)
  182. {
  183. if(null != m_iter)
  184. {
  185. XPathContext xctxt = (XPathContext)environment;
  186. m_dtmMgr = xctxt.getDTMManager();
  187. m_iter.setRoot(nodeHandle, environment);
  188. if(!m_iter.isDocOrdered())
  189. {
  190. if(!hasCache())
  191. setShouldCacheNodes(true);
  192. runTo(-1);
  193. m_next=0;
  194. }
  195. }
  196. else
  197. assertion(false, "Can not setRoot on a non-iterated NodeSequence!");
  198. }
  199. /**
  200. * @see DTMIterator#reset()
  201. */
  202. public void reset()
  203. {
  204. m_next = 0;
  205. // not resetting the iterator on purpose!!!
  206. }
  207. /**
  208. * @see DTMIterator#getWhatToShow()
  209. */
  210. public int getWhatToShow()
  211. {
  212. return hasCache() ? (DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE)
  213. : m_iter.getWhatToShow();
  214. }
  215. /**
  216. * @see DTMIterator#getExpandEntityReferences()
  217. */
  218. public boolean getExpandEntityReferences()
  219. {
  220. if(null != m_iter)
  221. return m_iter.getExpandEntityReferences();
  222. else
  223. return true;
  224. }
  225. /**
  226. * @see DTMIterator#nextNode()
  227. */
  228. public int nextNode()
  229. {
  230. // If the cache is on, and the node has already been found, then
  231. // just return from the list.
  232. NodeVector vec = getVector();
  233. if (null != vec)
  234. {
  235. if(m_next < vec.size())
  236. {
  237. int next = vec.elementAt(m_next);
  238. m_next++;
  239. return next;
  240. }
  241. else if((-1 != m_last) || (null == m_iter))
  242. {
  243. m_next++;
  244. return DTM.NULL;
  245. }
  246. }
  247. if (null == m_iter)
  248. return DTM.NULL;
  249. int next = m_iter.nextNode();
  250. if(DTM.NULL != next)
  251. {
  252. if(hasCache())
  253. {
  254. if(m_iter.isDocOrdered())
  255. {
  256. getVector().addElement(next);
  257. m_next++;
  258. }
  259. else
  260. {
  261. int insertIndex = addNodeInDocOrder(next);
  262. if(insertIndex >= 0)
  263. m_next++;
  264. }
  265. }
  266. else
  267. m_next++;
  268. }
  269. else
  270. {
  271. m_last = m_next;
  272. m_next++;
  273. }
  274. return next;
  275. }
  276. /**
  277. * @see DTMIterator#previousNode()
  278. */
  279. public int previousNode()
  280. {
  281. if(hasCache())
  282. {
  283. if(m_next <= 0)
  284. return DTM.NULL;
  285. else
  286. {
  287. m_next--;
  288. return item(m_next);
  289. }
  290. }
  291. else
  292. {
  293. int n = m_iter.previousNode();
  294. m_next = m_iter.getCurrentPos();
  295. return m_next;
  296. }
  297. }
  298. /**
  299. * @see DTMIterator#detach()
  300. */
  301. public void detach()
  302. {
  303. if(null != m_iter)
  304. m_iter.detach();
  305. super.detach();
  306. }
  307. /**
  308. * Calling this with a value of false will cause the nodeset
  309. * to be cached.
  310. * @see DTMIterator#allowDetachToRelease(boolean)
  311. */
  312. public void allowDetachToRelease(boolean allowRelease)
  313. {
  314. if((false == allowRelease) && !hasCache())
  315. {
  316. setShouldCacheNodes(true);
  317. }
  318. if(null != m_iter)
  319. m_iter.allowDetachToRelease(allowRelease);
  320. super.allowDetachToRelease(allowRelease);
  321. }
  322. /**
  323. * @see DTMIterator#getCurrentNode()
  324. */
  325. public int getCurrentNode()
  326. {
  327. if(hasCache())
  328. {
  329. int currentIndex = m_next-1;
  330. NodeVector vec = getVector();
  331. if((currentIndex >= 0) && (currentIndex < vec.size()))
  332. return vec.elementAt(currentIndex);
  333. else
  334. return DTM.NULL;
  335. }
  336. if(null != m_iter)
  337. {
  338. return m_iter.getCurrentNode();
  339. }
  340. else
  341. return DTM.NULL;
  342. }
  343. /**
  344. * @see DTMIterator#isFresh()
  345. */
  346. public boolean isFresh()
  347. {
  348. return (0 == m_next);
  349. }
  350. /**
  351. * @see DTMIterator#setShouldCacheNodes(boolean)
  352. */
  353. public void setShouldCacheNodes(boolean b)
  354. {
  355. if (b)
  356. {
  357. if(!hasCache())
  358. {
  359. SetVector(new NodeVector());
  360. }
  361. // else
  362. // getVector().RemoveAllNoClear(); // Is this good?
  363. }
  364. else
  365. SetVector(null);
  366. }
  367. /**
  368. * @see DTMIterator#isMutable()
  369. */
  370. public boolean isMutable()
  371. {
  372. return hasCache(); // though may be surprising if it also has an iterator!
  373. }
  374. /**
  375. * @see DTMIterator#getCurrentPos()
  376. */
  377. public int getCurrentPos()
  378. {
  379. return m_next;
  380. }
  381. /**
  382. * @see DTMIterator#runTo(int)
  383. */
  384. public void runTo(int index)
  385. {
  386. int n;
  387. if (-1 == index)
  388. {
  389. int pos = m_next;
  390. while (DTM.NULL != (n = nextNode()));
  391. m_next = pos;
  392. }
  393. else if(m_next == index)
  394. {
  395. return;
  396. }
  397. else if(hasCache() && m_next < getVector().size())
  398. {
  399. m_next = index;
  400. }
  401. else if((null == getVector()) && (index < m_next))
  402. {
  403. while ((m_next >= index) && DTM.NULL != (n = previousNode()));
  404. }
  405. else
  406. {
  407. while ((m_next < index) && DTM.NULL != (n = nextNode()));
  408. }
  409. }
  410. /**
  411. * @see DTMIterator#setCurrentPos(int)
  412. */
  413. public void setCurrentPos(int i)
  414. {
  415. runTo(i);
  416. }
  417. /**
  418. * @see DTMIterator#item(int)
  419. */
  420. public int item(int index)
  421. {
  422. setCurrentPos(index);
  423. int n = nextNode();
  424. m_next = index;
  425. return n;
  426. }
  427. /**
  428. * @see DTMIterator#setItem(int, int)
  429. */
  430. public void setItem(int node, int index)
  431. {
  432. NodeVector vec = getVector();
  433. if(null != vec)
  434. {
  435. vec.setElementAt(node, index);
  436. m_last = vec.size();
  437. }
  438. else
  439. m_iter.setItem(node, index);
  440. }
  441. /**
  442. * @see DTMIterator#getLength()
  443. */
  444. public int getLength()
  445. {
  446. if(hasCache())
  447. {
  448. // If this NodeSequence wraps a mutable nodeset, then
  449. // m_last will not reflect the size of the nodeset if
  450. // it has been mutated...
  451. if (m_iter instanceof NodeSetDTM)
  452. {
  453. return m_iter.getLength();
  454. }
  455. if(-1 == m_last)
  456. {
  457. int pos = m_next;
  458. runTo(-1);
  459. m_next = pos;
  460. }
  461. return m_last;
  462. }
  463. else
  464. {
  465. return (-1 == m_last) ? (m_last = m_iter.getLength()) : m_last;
  466. }
  467. }
  468. /**
  469. * Note: Not a deep clone.
  470. * @see DTMIterator#cloneWithReset()
  471. */
  472. public DTMIterator cloneWithReset() throws CloneNotSupportedException
  473. {
  474. NodeSequence seq = (NodeSequence)super.clone();
  475. seq.m_next = 0;
  476. return seq;
  477. }
  478. /**
  479. * Get a clone of this iterator, but don't reset the iteration in the
  480. * process, so that it may be used from the current position.
  481. * Note: Not a deep clone.
  482. *
  483. * @return A clone of this object.
  484. *
  485. * @throws CloneNotSupportedException
  486. */
  487. public Object clone() throws CloneNotSupportedException
  488. {
  489. return super.clone();
  490. }
  491. /**
  492. * @see DTMIterator#isDocOrdered()
  493. */
  494. public boolean isDocOrdered()
  495. {
  496. if(null != m_iter)
  497. return m_iter.isDocOrdered();
  498. else
  499. return true; // can't be sure?
  500. }
  501. /**
  502. * @see DTMIterator#getAxis()
  503. */
  504. public int getAxis()
  505. {
  506. if(null != m_iter)
  507. return m_iter.getAxis();
  508. else
  509. {
  510. assertion(false, "Can not getAxis from a non-iterated node sequence!");
  511. return 0;
  512. }
  513. }
  514. /**
  515. * @see PathComponent#getAnalysisBits()
  516. */
  517. public int getAnalysisBits()
  518. {
  519. if((null != m_iter) && (m_iter instanceof PathComponent))
  520. return ((PathComponent)m_iter).getAnalysisBits();
  521. else
  522. return 0;
  523. }
  524. /**
  525. * @see com.sun.org.apache.xpath.internal.Expression#fixupVariables(Vector, int)
  526. */
  527. public void fixupVariables(Vector vars, int globalsSize)
  528. {
  529. super.fixupVariables(vars, globalsSize);
  530. }
  531. /**
  532. * Add the node into a vector of nodes where it should occur in
  533. * document order.
  534. * @param v Vector of nodes, presumably containing Nodes
  535. * @param obj Node object.
  536. *
  537. * @param node The node to be added.
  538. * @param test true if we should test for doc order
  539. * @param support The XPath runtime context.
  540. * @return insertIndex.
  541. * @throws RuntimeException thrown if this NodeSetDTM is not of
  542. * a mutable type.
  543. */
  544. protected int addNodeInDocOrder(int node)
  545. {
  546. assertion(hasCache(), "addNodeInDocOrder must be done on a mutable sequence!");
  547. int insertIndex = -1;
  548. NodeVector vec = getVector();
  549. // This needs to do a binary search, but a binary search
  550. // is somewhat tough because the sequence test involves
  551. // two nodes.
  552. int size = vec.size(), i;
  553. for (i = size - 1; i >= 0; i--)
  554. {
  555. int child = vec.elementAt(i);
  556. if (child == node)
  557. {
  558. i = -2; // Duplicate, suppress insert
  559. break;
  560. }
  561. DTM dtm = m_dtmMgr.getDTM(node);
  562. if (!dtm.isNodeAfter(node, child))
  563. {
  564. break;
  565. }
  566. }
  567. if (i != -2)
  568. {
  569. insertIndex = i + 1;
  570. vec.insertElementAt(node, insertIndex);
  571. }
  572. // checkDups();
  573. return insertIndex;
  574. } // end addNodeInDocOrder(Vector v, Object obj)
  575. }