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.Iterator;
  18. import org.apache.commons.jxpath.ri.EvalContext;
  19. import org.apache.commons.jxpath.ri.InfoSetUtil;
  20. import org.apache.commons.jxpath.ri.compiler.Expression;
  21. import org.apache.commons.jxpath.ri.compiler.NameAttributeTest;
  22. import org.apache.commons.jxpath.ri.model.NodePointer;
  23. import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
  24. import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
  25. /**
  26. * EvalContext that checks predicates.
  27. *
  28. * @author Dmitri Plotnikov
  29. * @version $Revision: 1.22 $ $Date: 2004/02/29 14:17:37 $
  30. */
  31. public class PredicateContext extends EvalContext {
  32. private Expression expression;
  33. private boolean done = false;
  34. private Expression nameTestExpression;
  35. private PropertyPointer dynamicPropertyPointer;
  36. public PredicateContext(EvalContext parentContext, Expression expression) {
  37. super(parentContext);
  38. this.expression = expression;
  39. if (expression instanceof NameAttributeTest) {
  40. nameTestExpression =
  41. ((NameAttributeTest) expression).getNameTestExpression();
  42. }
  43. }
  44. public boolean nextNode() {
  45. if (done) {
  46. return false;
  47. }
  48. while (parentContext.nextNode()) {
  49. if (setupDynamicPropertyPointer()) {
  50. Object pred = nameTestExpression.computeValue(parentContext);
  51. String propertyName = InfoSetUtil.stringValue(pred);
  52. // At this point it would be nice to say:
  53. // dynamicPropertyPointer.setPropertyName(propertyName)
  54. // and then: dynamicPropertyPointer.isActual().
  55. // However some PropertyPointers, e.g. DynamicPropertyPointer
  56. // will declare that any property you ask for is actual.
  57. // That's not acceptable for us: we really need to know
  58. // if the property is currently declared. Thus,
  59. // we'll need to perform a search.
  60. boolean ok = false;
  61. String names[] = dynamicPropertyPointer.getPropertyNames();
  62. for (int i = 0; i < names.length; i++) {
  63. if (names[i].equals(propertyName)) {
  64. ok = true;
  65. break;
  66. }
  67. }
  68. if (ok) {
  69. dynamicPropertyPointer.setPropertyName(propertyName);
  70. position++;
  71. return true;
  72. }
  73. }
  74. else {
  75. Object pred = expression.computeValue(parentContext);
  76. if (pred instanceof Iterator) {
  77. if (!((Iterator) pred).hasNext()) {
  78. return false;
  79. }
  80. pred = ((Iterator) pred).next();
  81. }
  82. if (pred instanceof NodePointer) {
  83. pred = ((NodePointer) pred).getNode();
  84. }
  85. if (pred instanceof Number) {
  86. int pos = (int) InfoSetUtil.doubleValue(pred);
  87. position++;
  88. done = true;
  89. return parentContext.setPosition(pos);
  90. }
  91. else if (InfoSetUtil.booleanValue(pred)) {
  92. position++;
  93. return true;
  94. }
  95. }
  96. }
  97. return false;
  98. }
  99. /**
  100. * Used for an optimized access to dynamic properties using the
  101. * "map[@name = 'name']" syntax
  102. */
  103. private boolean setupDynamicPropertyPointer() {
  104. if (nameTestExpression == null) {
  105. return false;
  106. }
  107. NodePointer parent = parentContext.getCurrentNodePointer();
  108. if (parent == null) {
  109. return false;
  110. }
  111. parent = parent.getValuePointer();
  112. if (!(parent instanceof PropertyOwnerPointer)) {
  113. return false;
  114. }
  115. dynamicPropertyPointer =
  116. (PropertyPointer) ((PropertyOwnerPointer) parent)
  117. .getPropertyPointer()
  118. .clone();
  119. return true;
  120. }
  121. public boolean setPosition(int position) {
  122. if (nameTestExpression == null) {
  123. return setPositionStandard(position);
  124. }
  125. else {
  126. if (dynamicPropertyPointer == null) {
  127. if (!setupDynamicPropertyPointer()) {
  128. return setPositionStandard(position);
  129. }
  130. }
  131. if (position < 1
  132. || position > dynamicPropertyPointer.getLength()) {
  133. return false;
  134. }
  135. dynamicPropertyPointer.setIndex(position - 1);
  136. return true;
  137. }
  138. }
  139. public NodePointer getCurrentNodePointer() {
  140. if (position == 0) {
  141. if (!setPosition(1)) {
  142. return null;
  143. }
  144. }
  145. if (dynamicPropertyPointer != null) {
  146. return dynamicPropertyPointer.getValuePointer();
  147. }
  148. else {
  149. return parentContext.getCurrentNodePointer();
  150. }
  151. }
  152. public void reset() {
  153. super.reset();
  154. done = false;
  155. }
  156. public boolean nextSet() {
  157. reset();
  158. return parentContext.nextSet();
  159. }
  160. private boolean setPositionStandard(int position) {
  161. if (this.position > position) {
  162. reset();
  163. }
  164. while (this.position < position) {
  165. if (!nextNode()) {
  166. return false;
  167. }
  168. }
  169. return true;
  170. }
  171. }