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