    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 }