001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.jxpath.ri.axes;
018
019 import java.util.Iterator;
020
021 import org.apache.commons.jxpath.ri.EvalContext;
022 import org.apache.commons.jxpath.ri.InfoSetUtil;
023 import org.apache.commons.jxpath.ri.compiler.Expression;
024 import org.apache.commons.jxpath.ri.compiler.NameAttributeTest;
025 import org.apache.commons.jxpath.ri.model.NodePointer;
026 import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
027 import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
028
029 /**
030 * EvalContext that checks predicates.
031 *
032 * @author Dmitri Plotnikov
033 * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
034 */
035 public class PredicateContext extends EvalContext {
036 private Expression expression;
037 private boolean done = false;
038 private Expression nameTestExpression;
039 private PropertyPointer dynamicPropertyPointer;
040
041 /**
042 * Create a new PredicateContext.
043 * @param parentContext parent context
044 * @param expression compiled Expression
045 */
046 public PredicateContext(EvalContext parentContext, Expression expression) {
047 super(parentContext);
048 this.expression = expression;
049 if (expression instanceof NameAttributeTest) {
050 nameTestExpression =
051 ((NameAttributeTest) expression).getNameTestExpression();
052 }
053 }
054
055 public boolean nextNode() {
056 if (done) {
057 return false;
058 }
059 while (parentContext.nextNode()) {
060 if (setupDynamicPropertyPointer()) {
061 Object pred = nameTestExpression.computeValue(parentContext);
062 String propertyName = InfoSetUtil.stringValue(pred);
063
064 // At this point it would be nice to say:
065 // dynamicPropertyPointer.setPropertyName(propertyName)
066 // and then: dynamicPropertyPointer.isActual().
067 // However some PropertyPointers, e.g. DynamicPropertyPointer
068 // will declare that any property you ask for is actual.
069 // That's not acceptable for us: we really need to know
070 // if the property is currently declared. Thus,
071 // we'll need to perform a search.
072 boolean ok = false;
073 String[] names = dynamicPropertyPointer.getPropertyNames();
074 for (int i = 0; i < names.length; i++) {
075 if (names[i].equals(propertyName)) {
076 ok = true;
077 break;
078 }
079 }
080 if (ok) {
081 dynamicPropertyPointer.setPropertyName(propertyName);
082 position++;
083 return true;
084 }
085 }
086 else {
087 Object pred = expression.computeValue(parentContext);
088 if (pred instanceof Iterator) {
089 if (!((Iterator) pred).hasNext()) {
090 return false;
091 }
092 pred = ((Iterator) pred).next();
093 }
094
095 if (pred instanceof NodePointer) {
096 pred = ((NodePointer) pred).getNode();
097 }
098
099 if (pred instanceof Number) {
100 int pos = (int) InfoSetUtil.doubleValue(pred);
101 position++;
102 done = true;
103 return parentContext.setPosition(pos);
104 }
105 if (InfoSetUtil.booleanValue(pred)) {
106 position++;
107 return true;
108 }
109 }
110 }
111 return false;
112 }
113
114 /**
115 * Used for an optimized access to dynamic properties using the
116 * "map[@name = 'name']" syntax
117 * @return whether valid
118 */
119 private boolean setupDynamicPropertyPointer() {
120 if (nameTestExpression == null) {
121 return false;
122 }
123
124 NodePointer parent = parentContext.getCurrentNodePointer();
125 if (parent == null) {
126 return false;
127 }
128 parent = parent.getValuePointer();
129 if (!(parent instanceof PropertyOwnerPointer)) {
130 return false;
131 }
132 dynamicPropertyPointer =
133 (PropertyPointer) ((PropertyOwnerPointer) parent)
134 .getPropertyPointer()
135 .clone();
136 return true;
137 }
138
139 public boolean setPosition(int position) {
140 if (nameTestExpression == null) {
141 return setPositionStandard(position);
142 }
143 else {
144 if (dynamicPropertyPointer == null && !setupDynamicPropertyPointer()) {
145 return setPositionStandard(position);
146 }
147 if (position < 1
148 || position > dynamicPropertyPointer.getLength()) {
149 return false;
150 }
151 dynamicPropertyPointer.setIndex(position - 1);
152 return true;
153 }
154 }
155
156 public NodePointer getCurrentNodePointer() {
157 if (position == 0 && !setPosition(1)) {
158 return null;
159 }
160 if (dynamicPropertyPointer != null) {
161 return dynamicPropertyPointer.getValuePointer();
162 }
163 return parentContext.getCurrentNodePointer();
164 }
165
166 public void reset() {
167 super.reset();
168 parentContext.reset();
169 done = false;
170 }
171
172 public boolean nextSet() {
173 reset();
174 return parentContext.nextSet();
175 }
176
177 /**
178 * Basic setPosition
179 * @param position to set
180 * @return whether valid
181 */
182 private boolean setPositionStandard(int position) {
183 if (this.position > position) {
184 reset();
185 }
186
187 while (this.position < position) {
188 if (!nextNode()) {
189 return false;
190 }
191 }
192 return true;
193 }
194 }