View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jxpath.ri.axes;
18  
19  import java.util.Iterator;
20  
21  import org.apache.commons.jxpath.ri.EvalContext;
22  import org.apache.commons.jxpath.ri.InfoSetUtil;
23  import org.apache.commons.jxpath.ri.compiler.Expression;
24  import org.apache.commons.jxpath.ri.compiler.NameAttributeTest;
25  import org.apache.commons.jxpath.ri.model.NodePointer;
26  import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
27  import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
28  
29  /**
30   * EvalContext that checks predicates.
31   *
32   * @author Dmitri Plotnikov
33   * @version $Revision: 652845 $ $Date: 2008-05-02 19:46:46 +0200 (Fr, 02 Mai 2008) $
34   */
35  public class PredicateContext extends EvalContext {
36      private Expression expression;
37      private boolean done = false;
38      private Expression nameTestExpression;
39      private PropertyPointer dynamicPropertyPointer;
40  
41      /**
42       * Create a new PredicateContext.
43       * @param parentContext parent context
44       * @param expression compiled Expression
45       */
46      public PredicateContext(EvalContext parentContext, Expression expression) {
47          super(parentContext);
48          this.expression = expression;
49          if (expression instanceof NameAttributeTest) {
50              nameTestExpression =
51                  ((NameAttributeTest) expression).getNameTestExpression();
52          }
53      }
54  
55      public boolean nextNode() {
56          if (done) {
57              return false;
58          }
59          while (parentContext.nextNode()) {
60              if (setupDynamicPropertyPointer()) {
61                  Object pred = nameTestExpression.computeValue(parentContext);
62                  String propertyName = InfoSetUtil.stringValue(pred);
63  
64                  // At this point it would be nice to say:
65                  // dynamicPropertyPointer.setPropertyName(propertyName)
66                  // and then: dynamicPropertyPointer.isActual().
67                  // However some PropertyPointers, e.g. DynamicPropertyPointer
68                  // will declare that any property you ask for is actual.
69                  // That's not acceptable for us: we really need to know
70                  // if the property is currently declared. Thus,
71                  // we'll need to perform a search.
72                  boolean ok = false;
73                  String[] names = dynamicPropertyPointer.getPropertyNames();
74                  for (int i = 0; i < names.length; i++) {
75                      if (names[i].equals(propertyName)) {
76                          ok = true;
77                          break;
78                      }
79                  }
80                  if (ok) {
81                      dynamicPropertyPointer.setPropertyName(propertyName);
82                      position++;
83                      return true;
84                  }
85              }
86              else {
87                  Object pred = expression.computeValue(parentContext);
88                  if (pred instanceof Iterator) {
89                      if (!((Iterator) pred).hasNext()) {
90                          return false;
91                      }
92                      pred = ((Iterator) pred).next();
93                  }
94  
95                  if (pred instanceof NodePointer) {
96                      pred = ((NodePointer) pred).getNode();
97                  }
98  
99                  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 }