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. package org.apache.commons.jxpath.ri.axes;
  17. import java.util.Stack;
  18. import org.apache.commons.jxpath.Pointer;
  19. import org.apache.commons.jxpath.ri.Compiler;
  20. import org.apache.commons.jxpath.ri.EvalContext;
  21. import org.apache.commons.jxpath.ri.compiler.NodeTest;
  22. import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
  23. import org.apache.commons.jxpath.ri.model.NodeIterator;
  24. import org.apache.commons.jxpath.ri.model.NodePointer;
  25. /**
  26. * An EvalContext that walks the "descendant::" and "descendant-or-self::"
  27. * axes.
  28. *
  29. * @author Dmitri Plotnikov
  30. * @version $Revision: 1.16 $ $Date: 2004/02/29 14:17:38 $
  31. */
  32. public class DescendantContext extends EvalContext {
  33. private NodeTest nodeTest;
  34. private boolean setStarted = false;
  35. private Stack stack;
  36. private NodePointer currentNodePointer;
  37. private boolean includeSelf;
  38. private static final NodeTest ELEMENT_NODE_TEST =
  39. new NodeTypeTest(Compiler.NODE_TYPE_NODE);
  40. public DescendantContext(
  41. EvalContext parentContext,
  42. boolean includeSelf,
  43. NodeTest nodeTest)
  44. {
  45. super(parentContext);
  46. this.includeSelf = includeSelf;
  47. this.nodeTest = nodeTest;
  48. }
  49. public boolean isChildOrderingRequired() {
  50. return true;
  51. }
  52. public NodePointer getCurrentNodePointer() {
  53. if (position == 0) {
  54. if (!setPosition(1)) {
  55. return null;
  56. }
  57. }
  58. return currentNodePointer;
  59. }
  60. public void reset() {
  61. super.reset();
  62. setStarted = false;
  63. }
  64. public boolean setPosition(int position) {
  65. if (position < this.position) {
  66. reset();
  67. }
  68. while (this.position < position) {
  69. if (!nextNode()) {
  70. return false;
  71. }
  72. }
  73. return true;
  74. }
  75. public boolean nextNode() {
  76. if (!setStarted) {
  77. setStarted = true;
  78. stack = new Stack();
  79. currentNodePointer = parentContext.getCurrentNodePointer();
  80. if (currentNodePointer != null) {
  81. if (!currentNodePointer.isLeaf()) {
  82. stack.push(
  83. currentNodePointer.childIterator(
  84. ELEMENT_NODE_TEST,
  85. false,
  86. null));
  87. }
  88. if (includeSelf) {
  89. if (currentNodePointer.testNode(nodeTest)) {
  90. position++;
  91. return true;
  92. }
  93. }
  94. }
  95. }
  96. while (!stack.isEmpty()) {
  97. NodeIterator it = (NodeIterator) stack.peek();
  98. if (it.setPosition(it.getPosition() + 1)) {
  99. currentNodePointer = it.getNodePointer();
  100. if (!isRecursive()) {
  101. if (!currentNodePointer.isLeaf()) {
  102. stack.push(
  103. currentNodePointer.childIterator(
  104. ELEMENT_NODE_TEST,
  105. false,
  106. null));
  107. }
  108. if (currentNodePointer.testNode(nodeTest)) {
  109. position++;
  110. return true;
  111. }
  112. }
  113. }
  114. else {
  115. // We get here only if the name test failed
  116. // and the iterator ended
  117. stack.pop();
  118. }
  119. }
  120. return false;
  121. }
  122. /**
  123. * Checks if we are reentering a bean we have already seen and if so
  124. * returns true to prevent infinite recursion.
  125. */
  126. private boolean isRecursive() {
  127. Object node = currentNodePointer.getNode();
  128. for (int i = stack.size() - 1; --i >= 0;) {
  129. NodeIterator it = (NodeIterator) stack.get(i);
  130. Pointer pointer = it.getNodePointer();
  131. if (pointer != null && pointer.getNode() == node) {
  132. return true;
  133. }
  134. }
  135. return false;
  136. }
  137. }