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 */ 017package org.apache.commons.jxpath.ri.axes; 018 019import java.util.Iterator; 020 021import org.apache.commons.jxpath.ri.EvalContext; 022import org.apache.commons.jxpath.ri.InfoSetUtil; 023import org.apache.commons.jxpath.ri.compiler.Expression; 024import org.apache.commons.jxpath.ri.compiler.NameAttributeTest; 025import org.apache.commons.jxpath.ri.model.NodePointer; 026import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer; 027import 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 19:46:46 +0200 (Fr, 02 Mai 2008) $ 034 */ 035public 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}