1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package com.sun.org.apache.xpath.internal.axes; 22 23 import com.sun.org.apache.xml.internal.dtm.DTM; 24 import com.sun.org.apache.xml.internal.dtm.DTMFilter; 25 import com.sun.org.apache.xml.internal.dtm.DTMIterator; 26 import com.sun.org.apache.xml.internal.dtm.DTMManager; 27 import com.sun.org.apache.xml.internal.utils.NodeVector; 28 import com.sun.org.apache.xml.internal.utils.QName; 29 import com.sun.org.apache.xpath.internal.NodeSetDTM; 30 import com.sun.org.apache.xpath.internal.XPathContext; 31 import com.sun.org.apache.xpath.internal.objects.XObject; 32 import java.util.List; 33 34 /** 35 * This class is the dynamic wrapper for a Xalan DTMIterator instance, and 36 * provides random access capabilities. 37 * 38 * @LastModified: Oct 2017 39 */ 40 public class NodeSequence extends XObject 41 implements DTMIterator, Cloneable, PathComponent 42 { 43 static final long serialVersionUID = 3866261934726581044L; 44 /** The index of the last node in the iteration. */ 45 protected int m_last = -1; 46 47 /** 48 * The index of the next node to be fetched. Useful if this 49 * is a cached iterator, and is being used as random access 50 * NodeList. 51 */ 52 protected int m_next = 0; 53 54 /** 55 * A cache of a list of nodes obtained from the iterator so far. 56 * This list is appended to until the iterator is exhausted and 57 * the cache is complete. 58 * <p> 59 * Multiple NodeSequence objects may share the same cache. 60 */ 61 private IteratorCache m_cache; 62 63 /** 64 * If this iterator needs to cache nodes that are fetched, they 65 * are stored in the Vector in the generic object. 66 */ 67 protected NodeVector getVector() { 68 NodeVector nv = (m_cache != null) ? m_cache.getVector() : null; 69 return nv; 70 } 71 72 /** 73 * Get the cache (if any) of nodes obtained from 74 * the iterator so far. Note that the cache keeps 75 * growing until the iterator is walked to exhaustion, 76 * at which point the cache is "complete". 77 */ 78 private IteratorCache getCache() { 79 return m_cache; 80 } 81 82 /** 83 * Set the vector where nodes will be cached. 84 */ 85 protected void SetVector(NodeVector v) 86 { 87 setObject(v); 88 } 89 90 91 /** 92 * If the iterator needs to cache nodes as they are fetched, 93 * then this method returns true. 94 */ 95 public boolean hasCache() 96 { 97 final NodeVector nv = getVector(); 98 return (nv != null); 99 } 100 101 /** 102 * If this NodeSequence has a cache, and that cache is 103 * fully populated then this method returns true, otherwise 104 * if there is no cache or it is not complete it returns false. 105 */ 106 private boolean cacheComplete() { 107 final boolean complete; 108 if (m_cache != null) { 109 complete = m_cache.isComplete(); 110 } else { 111 complete = false; 112 } 113 return complete; 114 } 115 116 /** 117 * If this NodeSequence has a cache, mark that it is complete. 118 * This method should be called after the iterator is exhausted. 119 */ 120 private void markCacheComplete() { 121 NodeVector nv = getVector(); 122 if (nv != null) { 123 m_cache.setCacheComplete(true); 124 } 125 } 126 127 128 /** 129 * The functional iterator that fetches nodes. 130 */ 131 protected DTMIterator m_iter; 132 133 /** 134 * Set the functional iterator that fetches nodes. 135 * @param iter The iterator that is to be contained. 136 */ 137 public final void setIter(DTMIterator iter) 138 { 139 m_iter = iter; 140 } 141 142 /** 143 * Get the functional iterator that fetches nodes. 144 * @return The contained iterator. 145 */ 146 public final DTMIterator getContainedIter() 147 { 148 return m_iter; 149 } 150 151 /** 152 * The DTMManager to use if we're using a NodeVector only. 153 * We may well want to do away with this, and store it in the NodeVector. 154 */ 155 protected DTMManager m_dtmMgr; 156 157 // ==== Constructors ==== 158 159 /** 160 * Create a new NodeSequence from a (already cloned) iterator. 161 * 162 * @param iter Cloned (not static) DTMIterator. 163 * @param context The initial context node. 164 * @param xctxt The execution context. 165 * @param shouldCacheNodes True if this sequence can random access. 166 */ 167 private NodeSequence(DTMIterator iter, int context, XPathContext xctxt, boolean shouldCacheNodes) 168 { 169 setIter(iter); 170 setRoot(context, xctxt); 171 setShouldCacheNodes(shouldCacheNodes); 172 } 173 174 /** 175 * Create a new NodeSequence from a (already cloned) iterator. 176 * 177 * @param nodeVector 178 */ 179 public NodeSequence(Object nodeVector) 180 { 181 super(nodeVector); 182 if (nodeVector instanceof NodeVector) { 183 SetVector((NodeVector) nodeVector); 184 } 185 if(null != nodeVector) 186 { 187 assertion(nodeVector instanceof NodeVector, 188 "Must have a NodeVector as the object for NodeSequence!"); 189 if(nodeVector instanceof DTMIterator) 190 { 191 setIter((DTMIterator)nodeVector); 192 m_last = ((DTMIterator)nodeVector).getLength(); 193 } 194 195 } 196 } 197 198 /** 199 * Construct an empty XNodeSet object. This is used to create a mutable 200 * nodeset to which random nodes may be added. 201 */ 202 private NodeSequence(DTMManager dtmMgr) 203 { 204 super(new NodeVector()); 205 m_last = 0; 206 m_dtmMgr = dtmMgr; 207 } 208 209 210 /** 211 * Create a new NodeSequence in an invalid (null) state. 212 */ 213 public NodeSequence() 214 { 215 return; 216 } 217 218 219 /** 220 * @see DTMIterator#getDTM(int) 221 */ 222 public DTM getDTM(int nodeHandle) 223 { 224 DTMManager mgr = getDTMManager(); 225 if(null != mgr) 226 return getDTMManager().getDTM(nodeHandle); 227 else 228 { 229 assertion(false, "Can not get a DTM Unless a DTMManager has been set!"); 230 return null; 231 } 232 } 233 234 /** 235 * @see DTMIterator#getDTMManager() 236 */ 237 public DTMManager getDTMManager() 238 { 239 return m_dtmMgr; 240 } 241 242 /** 243 * @see DTMIterator#getRoot() 244 */ 245 public int getRoot() 246 { 247 if(null != m_iter) 248 return m_iter.getRoot(); 249 else 250 { 251 // NodeSetDTM will call this, and so it's not a good thing to throw 252 // an assertion here. 253 // assertion(false, "Can not get the root from a non-iterated NodeSequence!"); 254 return DTM.NULL; 255 } 256 } 257 258 /** 259 * @see DTMIterator#setRoot(int, Object) 260 */ 261 public void setRoot(int nodeHandle, Object environment) 262 { 263 // If root is DTM.NULL, then something's wrong with the context 264 if (nodeHandle == DTM.NULL) 265 { 266 throw new RuntimeException("Unable to evaluate expression using " + 267 "this context"); 268 } 269 270 if(null != m_iter) 271 { 272 XPathContext xctxt = (XPathContext)environment; 273 m_dtmMgr = xctxt.getDTMManager(); 274 m_iter.setRoot(nodeHandle, environment); 275 if(!m_iter.isDocOrdered()) 276 { 277 if(!hasCache()) 278 setShouldCacheNodes(true); 279 runTo(-1); 280 m_next=0; 281 } 282 } 283 else 284 assertion(false, "Can not setRoot on a non-iterated NodeSequence!"); 285 } 286 287 /** 288 * @see DTMIterator#reset() 289 */ 290 public void reset() 291 { 292 m_next = 0; 293 // not resetting the iterator on purpose!!! 294 } 295 296 /** 297 * @see DTMIterator#getWhatToShow() 298 */ 299 public int getWhatToShow() 300 { 301 return hasCache() ? (DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE) 302 : m_iter.getWhatToShow(); 303 } 304 305 /** 306 * @see DTMIterator#getExpandEntityReferences() 307 */ 308 public boolean getExpandEntityReferences() 309 { 310 if(null != m_iter) 311 return m_iter.getExpandEntityReferences(); 312 else 313 return true; 314 } 315 316 /** 317 * @see DTMIterator#nextNode() 318 */ 319 public int nextNode() 320 { 321 // If the cache is on, and the node has already been found, then 322 // just return from the list. 323 NodeVector vec = getVector(); 324 if (null != vec) 325 { 326 // There is a cache 327 if(m_next < vec.size()) 328 { 329 // The node is in the cache, so just return it. 330 int next = vec.elementAt(m_next); 331 m_next++; 332 return next; 333 } 334 else if(cacheComplete() || (-1 != m_last) || (null == m_iter)) 335 { 336 m_next++; 337 return DTM.NULL; 338 } 339 } 340 341 if (null == m_iter) 342 return DTM.NULL; 343 344 int next = m_iter.nextNode(); 345 if(DTM.NULL != next) 346 { 347 if(hasCache()) 348 { 349 if(m_iter.isDocOrdered()) 350 { 351 getVector().addElement(next); 352 m_next++; 353 } 354 else 355 { 356 int insertIndex = addNodeInDocOrder(next); 357 if(insertIndex >= 0) 358 m_next++; 359 } 360 } 361 else 362 m_next++; 363 } 364 else 365 { 366 // We have exhausted the iterator, and if there is a cache 367 // it must have all nodes in it by now, so let the cache 368 // know that it is complete. 369 markCacheComplete(); 370 371 m_last = m_next; 372 m_next++; 373 } 374 375 return next; 376 } 377 378 /** 379 * @see DTMIterator#previousNode() 380 */ 381 public int previousNode() 382 { 383 if(hasCache()) 384 { 385 if(m_next <= 0) 386 return DTM.NULL; 387 else 388 { 389 m_next--; 390 return item(m_next); 391 } 392 } 393 else 394 { 395 int n = m_iter.previousNode(); 396 m_next = m_iter.getCurrentPos(); 397 return m_next; 398 } 399 } 400 401 /** 402 * @see DTMIterator#detach() 403 */ 404 public void detach() 405 { 406 if(null != m_iter) 407 m_iter.detach(); 408 super.detach(); 409 } 410 411 /** 412 * Calling this with a value of false will cause the nodeset 413 * to be cached. 414 * @see DTMIterator#allowDetachToRelease(boolean) 415 */ 416 public void allowDetachToRelease(boolean allowRelease) 417 { 418 if((false == allowRelease) && !hasCache()) 419 { 420 setShouldCacheNodes(true); 421 } 422 423 if(null != m_iter) 424 m_iter.allowDetachToRelease(allowRelease); 425 super.allowDetachToRelease(allowRelease); 426 } 427 428 /** 429 * @see DTMIterator#getCurrentNode() 430 */ 431 public int getCurrentNode() 432 { 433 if(hasCache()) 434 { 435 int currentIndex = m_next-1; 436 NodeVector vec = getVector(); 437 if((currentIndex >= 0) && (currentIndex < vec.size())) 438 return vec.elementAt(currentIndex); 439 else 440 return DTM.NULL; 441 } 442 443 if(null != m_iter) 444 { 445 return m_iter.getCurrentNode(); 446 } 447 else 448 return DTM.NULL; 449 } 450 451 /** 452 * @see DTMIterator#isFresh() 453 */ 454 public boolean isFresh() 455 { 456 return (0 == m_next); 457 } 458 459 /** 460 * @see DTMIterator#setShouldCacheNodes(boolean) 461 */ 462 public void setShouldCacheNodes(boolean b) 463 { 464 if (b) 465 { 466 if(!hasCache()) 467 { 468 SetVector(new NodeVector()); 469 } 470 // else 471 // getVector().RemoveAllNoClear(); // Is this good? 472 } 473 else 474 SetVector(null); 475 } 476 477 /** 478 * @see DTMIterator#isMutable() 479 */ 480 public boolean isMutable() 481 { 482 return hasCache(); // though may be surprising if it also has an iterator! 483 } 484 485 /** 486 * @see DTMIterator#getCurrentPos() 487 */ 488 public int getCurrentPos() 489 { 490 return m_next; 491 } 492 493 /** 494 * @see DTMIterator#runTo(int) 495 */ 496 public void runTo(int index) 497 { 498 int n; 499 500 if (-1 == index) 501 { 502 int pos = m_next; 503 while (DTM.NULL != (n = nextNode())); 504 m_next = pos; 505 } 506 else if(m_next == index) 507 { 508 return; 509 } 510 else if(hasCache() && index < getVector().size()) 511 { 512 m_next = index; 513 } 514 else if((null == getVector()) && (index < m_next)) 515 { 516 while ((m_next >= index) && DTM.NULL != (n = previousNode())); 517 } 518 else 519 { 520 while ((m_next < index) && DTM.NULL != (n = nextNode())); 521 } 522 523 } 524 525 /** 526 * @see DTMIterator#setCurrentPos(int) 527 */ 528 public void setCurrentPos(int i) 529 { 530 runTo(i); 531 } 532 533 /** 534 * @see DTMIterator#item(int) 535 */ 536 public int item(int index) 537 { 538 setCurrentPos(index); 539 int n = nextNode(); 540 m_next = index; 541 return n; 542 } 543 544 /** 545 * @see DTMIterator#setItem(int, int) 546 */ 547 public void setItem(int node, int index) 548 { 549 NodeVector vec = getVector(); 550 if(null != vec) 551 { 552 int oldNode = vec.elementAt(index); 553 if (oldNode != node && m_cache.useCount() > 1) { 554 /* If we are going to set the node at the given index 555 * to a different value, and the cache is shared 556 * (has a use count greater than 1) 557 * then make a copy of the cache and use it 558 * so we don't overwrite the value for other 559 * users of the cache. 560 */ 561 IteratorCache newCache = new IteratorCache(); 562 final NodeVector nv; 563 try { 564 nv = (NodeVector) vec.clone(); 565 } catch (CloneNotSupportedException e) { 566 // This should never happen 567 e.printStackTrace(); 568 RuntimeException rte = new RuntimeException(e.getMessage()); 569 throw rte; 570 } 571 newCache.setVector(nv); 572 newCache.setCacheComplete(true); 573 m_cache = newCache; 574 vec = nv; 575 576 // Keep our superclass informed of the current NodeVector 577 super.setObject(nv); 578 579 /* When we get to here the new cache has 580 * a use count of 1 and when setting a 581 * bunch of values on the same NodeSequence, 582 * such as when sorting, we will keep setting 583 * values in that same copy which has a use count of 1. 584 */ 585 } 586 vec.setElementAt(node, index); 587 m_last = vec.size(); 588 } 589 else 590 m_iter.setItem(node, index); 591 } 592 593 /** 594 * @see DTMIterator#getLength() 595 */ 596 public int getLength() 597 { 598 IteratorCache cache = getCache(); 599 600 if(cache != null) 601 { 602 // Nodes from the iterator are cached 603 if (cache.isComplete()) { 604 // All of the nodes from the iterator are cached 605 // so just return the number of nodes in the cache 606 NodeVector nv = cache.getVector(); 607 return nv.size(); 608 } 609 610 // If this NodeSequence wraps a mutable nodeset, then 611 // m_last will not reflect the size of the nodeset if 612 // it has been mutated... 613 if (m_iter instanceof NodeSetDTM) 614 { 615 return m_iter.getLength(); 616 } 617 618 if(-1 == m_last) 619 { 620 int pos = m_next; 621 runTo(-1); 622 m_next = pos; 623 } 624 return m_last; 625 } 626 else 627 { 628 return (-1 == m_last) ? (m_last = m_iter.getLength()) : m_last; 629 } 630 } 631 632 /** 633 * Note: Not a deep clone. 634 * @see DTMIterator#cloneWithReset() 635 */ 636 public DTMIterator cloneWithReset() throws CloneNotSupportedException 637 { 638 NodeSequence seq = (NodeSequence)super.clone(); 639 seq.m_next = 0; 640 if (m_cache != null) { 641 // In making this clone of an iterator we are making 642 // another NodeSequence object it has a reference 643 // to the same IteratorCache object as the original 644 // so we need to remember that more than one 645 // NodeSequence object shares the cache. 646 m_cache.increaseUseCount(); 647 } 648 649 return seq; 650 } 651 652 /** 653 * Get a clone of this iterator, but don't reset the iteration in the 654 * process, so that it may be used from the current position. 655 * Note: Not a deep clone. 656 * 657 * @return A clone of this object. 658 * 659 * @throws CloneNotSupportedException 660 */ 661 public Object clone() throws CloneNotSupportedException 662 { 663 NodeSequence clone = (NodeSequence) super.clone(); 664 if (null != m_iter) clone.m_iter = (DTMIterator) m_iter.clone(); 665 if (m_cache != null) { 666 // In making this clone of an iterator we are making 667 // another NodeSequence object it has a reference 668 // to the same IteratorCache object as the original 669 // so we need to remember that more than one 670 // NodeSequence object shares the cache. 671 m_cache.increaseUseCount(); 672 } 673 674 return clone; 675 } 676 677 678 /** 679 * @see DTMIterator#isDocOrdered() 680 */ 681 public boolean isDocOrdered() 682 { 683 if(null != m_iter) 684 return m_iter.isDocOrdered(); 685 else 686 return true; // can't be sure? 687 } 688 689 /** 690 * @see DTMIterator#getAxis() 691 */ 692 public int getAxis() 693 { 694 if(null != m_iter) 695 return m_iter.getAxis(); 696 else 697 { 698 assertion(false, "Can not getAxis from a non-iterated node sequence!"); 699 return 0; 700 } 701 } 702 703 /** 704 * @see PathComponent#getAnalysisBits() 705 */ 706 public int getAnalysisBits() 707 { 708 if((null != m_iter) && (m_iter instanceof PathComponent)) 709 return ((PathComponent)m_iter).getAnalysisBits(); 710 else 711 return 0; 712 } 713 714 /** 715 * @see org.apache.xpath.Expression#fixupVariables(Vector, int) 716 */ 717 public void fixupVariables(List<QName> vars, int globalsSize) 718 { 719 super.fixupVariables(vars, globalsSize); 720 } 721 722 /** 723 * Add the node into a vector of nodes where it should occur in 724 * document order. 725 * @param node The node to be added. 726 * @return insertIndex. 727 * @throws RuntimeException thrown if this NodeSetDTM is not of 728 * a mutable type. 729 */ 730 protected int addNodeInDocOrder(int node) 731 { 732 assertion(hasCache(), "addNodeInDocOrder must be done on a mutable sequence!"); 733 734 int insertIndex = -1; 735 736 NodeVector vec = getVector(); 737 738 // This needs to do a binary search, but a binary search 739 // is somewhat tough because the sequence test involves 740 // two nodes. 741 int size = vec.size(), i; 742 743 for (i = size - 1; i >= 0; i--) 744 { 745 int child = vec.elementAt(i); 746 747 if (child == node) 748 { 749 i = -2; // Duplicate, suppress insert 750 751 break; 752 } 753 754 DTM dtm = m_dtmMgr.getDTM(node); 755 if (!dtm.isNodeAfter(node, child)) 756 { 757 break; 758 } 759 } 760 761 if (i != -2) 762 { 763 insertIndex = i + 1; 764 765 vec.insertElementAt(node, insertIndex); 766 } 767 768 // checkDups(); 769 return insertIndex; 770 } // end addNodeInDocOrder(List<QName> v, Object obj) 771 772 /** 773 * It used to be that many locations in the code simply 774 * did an assignment to this.m_obj directly, rather than 775 * calling the setObject(Object) method. The problem is 776 * that our super-class would be updated on what the 777 * cache associated with this NodeSequence, but 778 * we wouldn't know ourselves. 779 * <p> 780 * All setting of m_obj is done through setObject() now, 781 * and this method over-rides the super-class method. 782 * So now we are in the loop have an opportunity 783 * to update some caching information. 784 * 785 */ 786 protected void setObject(Object obj) { 787 if (obj instanceof NodeVector) { 788 // Keep our superclass informed of the current NodeVector 789 // ... if we don't the smoketest fails (don't know why). 790 super.setObject(obj); 791 792 // A copy of the code of what SetVector() would do. 793 NodeVector v = (NodeVector)obj; 794 if (m_cache != null) { 795 m_cache.setVector(v); 796 } else if (v!=null) { 797 m_cache = new IteratorCache(); 798 m_cache.setVector(v); 799 } 800 } else if (obj instanceof IteratorCache) { 801 IteratorCache cache = (IteratorCache) obj; 802 m_cache = cache; 803 m_cache.increaseUseCount(); 804 805 // Keep our superclass informed of the current NodeVector 806 super.setObject(cache.getVector()); 807 } else { 808 super.setObject(obj); 809 } 810 811 } 812 813 /** 814 * Each NodeSequence object has an iterator which is "walked". 815 * As an iterator is walked one obtains nodes from it. 816 * As those nodes are obtained they may be cached, making 817 * the next walking of a copy or clone of the iterator faster. 818 * This field (m_cache) is a reference to such a cache, 819 * which is populated as the iterator is walked. 820 * <p> 821 * Note that multiple NodeSequence objects may hold a 822 * reference to the same cache, and also 823 * (and this is important) the same iterator. 824 * The iterator and its cache may be shared among 825 * many NodeSequence objects. 826 * <p> 827 * If one of the NodeSequence objects walks ahead 828 * of the others it fills in the cache. 829 * As the others NodeSequence objects catch up they 830 * get their values from 831 * the cache rather than the iterator itself, so 832 * the iterator is only ever walked once and everyone 833 * benefits from the cache. 834 * <p> 835 * At some point the cache may be 836 * complete due to walking to the end of one of 837 * the copies of the iterator, and the cache is 838 * then marked as "complete". 839 * and the cache will have no more nodes added to it. 840 * <p> 841 * Its use-count is the number of NodeSequence objects that use it. 842 */ 843 private final static class IteratorCache { 844 /** 845 * A list of nodes already obtained from the iterator. 846 * As the iterator is walked the nodes obtained from 847 * it are appended to this list. 848 * <p> 849 * Both an iterator and its corresponding cache can 850 * be shared by multiple NodeSequence objects. 851 * <p> 852 * For example, consider three NodeSequence objects 853 * ns1, ns2 and ns3 doing such sharing, and the 854 * nodes to be obtaind from the iterator being 855 * the sequence { 33, 11, 44, 22, 55 }. 856 * <p> 857 * If ns3.nextNode() is called 3 times the the 858 * underlying iterator will have walked through 859 * 33, 11, 55 and these three nodes will have been put 860 * in the cache. 861 * <p> 862 * If ns2.nextNode() is called 2 times it will return 863 * 33 and 11 from the cache, leaving the iterator alone. 864 * <p> 865 * If ns1.nextNode() is called 6 times it will return 866 * 33 and 11 from the cache, then get 44, 22, 55 from 867 * the iterator, and appending 44, 22, 55 to the cache. 868 * On the sixth call it is found that the iterator is 869 * exhausted and the cache is marked complete. 870 * <p> 871 * Should ns2 or ns3 have nextNode() called they will 872 * know that the cache is complete, and they will 873 * obtain all subsequent nodes from the cache. 874 * <p> 875 * Note that the underlying iterator, though shared 876 * is only ever walked once. 877 */ 878 private NodeVector m_vec2; 879 880 /** 881 * true if the associated iterator is exhausted and 882 * all nodes obtained from it are in the cache. 883 */ 884 private boolean m_isComplete2; 885 886 private int m_useCount2; 887 888 IteratorCache() { 889 m_vec2 = null; 890 m_isComplete2 = false; 891 m_useCount2 = 1; 892 return; 893 } 894 895 /** 896 * Returns count of how many NodeSequence objects share this 897 * IteratorCache object. 898 */ 899 private int useCount() { 900 return m_useCount2; 901 } 902 903 /** 904 * This method is called when yet another 905 * NodeSequence object uses, or shares 906 * this same cache. 907 * 908 */ 909 private void increaseUseCount() { 910 if (m_vec2 != null) 911 m_useCount2++; 912 913 } 914 915 /** 916 * Sets the NodeVector that holds the 917 * growing list of nodes as they are appended 918 * to the cached list. 919 */ 920 private void setVector(NodeVector nv) { 921 m_vec2 = nv; 922 m_useCount2 = 1; 923 } 924 925 /** 926 * Get the cached list of nodes obtained from 927 * the iterator so far. 928 */ 929 private NodeVector getVector() { 930 return m_vec2; 931 } 932 933 /** 934 * Call this method with 'true' if the 935 * iterator is exhausted and the cached list 936 * is complete, or no longer growing. 937 */ 938 private void setCacheComplete(boolean b) { 939 m_isComplete2 = b; 940 941 } 942 943 /** 944 * Returns true if no cache is complete 945 * and immutable. 946 */ 947 private boolean isComplete() { 948 return m_isComplete2; 949 } 950 } 951 952 /** 953 * Get the cached list of nodes appended with 954 * values obtained from the iterator as 955 * a NodeSequence is walked when its 956 * nextNode() method is called. 957 */ 958 protected IteratorCache getIteratorCache() { 959 return m_cache; 960 } 961 }