View Javadoc

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