1 16 package org.apache.commons.jxpath.ri.model; 17 18 import org.apache.commons.jxpath.AbstractFactory; 19 import org.apache.commons.jxpath.JXPathContext; 20 import org.apache.commons.jxpath.JXPathException; 21 import org.apache.commons.jxpath.JXPathIntrospector; 22 import org.apache.commons.jxpath.Variables; 23 import org.apache.commons.jxpath.ri.QName; 24 import org.apache.commons.jxpath.ri.compiler.NodeTest; 25 import org.apache.commons.jxpath.ri.model.beans.NullPointer; 26 import org.apache.commons.jxpath.util.ValueUtils; 27 28 34 public class VariablePointer extends NodePointer { 35 private Variables variables; 36 private QName name; 37 private NodePointer valuePointer; 38 private boolean actual; 39 40 public VariablePointer(Variables variables, QName name) { 41 super(null); 42 this.variables = variables; 43 this.name = name; 44 actual = true; 45 } 46 47 public VariablePointer(QName name) { 48 super(null); 49 this.name = name; 50 actual = false; 51 } 52 53 public boolean isContainer() { 54 return true; 55 } 56 57 public QName getName() { 58 return name; 59 } 60 61 public Object getBaseValue() { 62 if (!actual) { 63 throw new JXPathException("Undefined variable: " + name); 64 } 65 return variables.getVariable(name.toString()); 66 } 67 68 public boolean isLeaf() { 69 Object value = getNode(); 70 return value == null 71 || JXPathIntrospector.getBeanInfo(value.getClass()).isAtomic(); 72 } 73 74 public boolean isCollection() { 75 Object value = getBaseValue(); 76 return value != null && ValueUtils.isCollection(value); 77 } 78 79 public Object getImmediateNode() { 80 Object value = getBaseValue(); 81 if (index != WHOLE_COLLECTION) { 82 return ValueUtils.getValue(value, index); 83 } 84 else { 85 return ValueUtils.getValue(value); 86 } 87 } 88 89 public void setValue(Object value) { 90 if (!actual) { 91 throw new JXPathException("Cannot set undefined variable: " + name); 92 } 93 valuePointer = null; 94 if (index != WHOLE_COLLECTION) { 95 Object collection = getBaseValue(); 96 ValueUtils.setValue(collection, index, value); 97 } 98 else { 99 variables.declareVariable(name.toString(), value); 100 } 101 } 102 103 public boolean isActual() { 104 return actual; 105 } 106 107 public void setIndex(int index) { 108 super.setIndex(index); 109 valuePointer = null; 110 } 111 112 public NodePointer getImmediateValuePointer() { 113 if (valuePointer == null) { 114 Object value = null; 115 if (actual) { 116 value = getImmediateNode(); 117 valuePointer = 118 NodePointer.newChildNodePointer(this, null, value); 119 } 120 else { 121 return new NullPointer(this, getName()) { 122 public Object getImmediateNode() { 123 throw new JXPathException( 124 "Undefined variable: " + name); 125 } 126 }; 127 } 128 } 129 return valuePointer; 130 } 131 132 public int getLength() { 133 if (actual) { 134 Object value = getBaseValue(); 135 if (value == null) { 136 return 1; 137 } 138 return ValueUtils.getLength(value); 139 } 140 return 0; 141 } 142 143 public NodePointer createPath(JXPathContext context, Object value) { 144 if (actual) { 145 setValue(value); 146 return this; 147 } 148 NodePointer ptr = createPath(context); 149 ptr.setValue(value); 150 return ptr; 151 } 152 153 public NodePointer createPath(JXPathContext context) { 154 if (!actual) { 155 AbstractFactory factory = getAbstractFactory(context); 156 if (!factory.declareVariable(context, name.toString())) { 157 throw new JXPathException( 158 "Factory cannot define variable '" 159 + name 160 + "' for path: " 161 + asPath()); 162 } 163 findVariables(context); 164 } 166 return this; 167 } 168 169 public NodePointer createChild( 170 JXPathContext context, 171 QName name, 172 int index) 173 { 174 Object collection = createCollection(context, index); 175 if (!isActual() || (index != 0 && index != WHOLE_COLLECTION)) { 176 AbstractFactory factory = getAbstractFactory(context); 177 boolean success = 178 factory.createObject( 179 context, 180 this, 181 collection, 182 getName().toString(), 183 index); 184 if (!success) { 185 throw new JXPathException( 186 "Factory could not create object path: " + asPath()); 187 } 188 NodePointer cln = (NodePointer) clone(); 189 cln.setIndex(index); 190 return cln; 191 } 192 return this; 193 } 194 195 public NodePointer createChild( 196 JXPathContext context, 197 QName name, 198 int index, 199 Object value) 200 { 201 Object collection = createCollection(context, index); 202 ValueUtils.setValue(collection, index, value); 203 NodePointer cl = (NodePointer) clone(); 204 cl.setIndex(index); 205 return cl; 206 } 207 208 private Object createCollection(JXPathContext context, int index) { 209 createPath(context); 210 211 Object collection = getBaseValue(); 212 if (collection == null) { 213 throw new JXPathException( 214 "Factory did not assign a collection to variable '" 215 + name 216 + "' for path: " 217 + asPath()); 218 } 219 220 if (index == WHOLE_COLLECTION) { 221 index = 0; 222 } 223 else if (index < 0) { 224 throw new JXPathException("Index is less than 1: " + asPath()); 225 } 226 227 if (index >= getLength()) { 228 collection = ValueUtils.expandCollection(collection, index + 1); 229 variables.declareVariable(name.toString(), collection); 230 } 231 232 return collection; 233 } 234 235 public void remove() { 236 if (actual) { 237 if (index == WHOLE_COLLECTION) { 238 variables.undeclareVariable(name.toString()); 239 } 240 else { 241 if (index < 0) { 242 throw new JXPathException( 243 "Index is less than 1: " + asPath()); 244 } 245 246 Object collection = getBaseValue(); 247 if (collection != null && index < getLength()) { 248 collection = ValueUtils.remove(collection, index); 249 variables.declareVariable(name.toString(), collection); 250 } 251 } 252 } 253 } 254 255 protected void findVariables(JXPathContext context) { 256 valuePointer = null; 257 JXPathContext varCtx = context; 258 while (varCtx != null) { 259 variables = varCtx.getVariables(); 260 if (variables.isDeclaredVariable(name.toString())) { 261 actual = true; 262 break; 263 } 264 varCtx = varCtx.getParentContext(); 265 variables = null; 266 } 267 } 268 269 public int hashCode() { 270 return (actual ? System.identityHashCode(variables) : 0) 271 + name.hashCode() 272 + index; 273 } 274 275 public boolean equals(Object object) { 276 if (object == this) { 277 return true; 278 } 279 280 if (!(object instanceof VariablePointer)) { 281 return false; 282 } 283 284 VariablePointer other = (VariablePointer) object; 285 return variables == other.variables 286 && name.equals(other.name) 287 && index == other.index; 288 } 289 290 public String asPath() { 291 StringBuffer buffer = new StringBuffer (); 292 buffer.append('$'); 293 buffer.append(name); 294 if (!actual) { 295 if (index != WHOLE_COLLECTION) { 296 buffer.append('[').append(index + 1).append(']'); 297 } 298 } 299 else if ( 300 index != WHOLE_COLLECTION 301 && (getNode() == null || isCollection())) { 302 buffer.append('[').append(index + 1).append(']'); 303 } 304 return buffer.toString(); 305 } 306 307 public NodeIterator childIterator( 308 NodeTest test, 309 boolean reverse, 310 NodePointer startWith) 311 { 312 return getValuePointer().childIterator(test, reverse, startWith); 313 } 314 315 public NodeIterator attributeIterator(QName name) { 316 return getValuePointer().attributeIterator(name); 317 } 318 319 public NodeIterator namespaceIterator() { 320 return getValuePointer().namespaceIterator(); 321 } 322 323 public NodePointer namespacePointer(String name) { 324 return getValuePointer().namespacePointer(name); 325 } 326 327 public boolean testNode(NodeTest nodeTest) { 328 return getValuePointer().testNode(nodeTest); 329 } 330 331 private AbstractFactory getAbstractFactory(JXPathContext context) { 332 AbstractFactory factory = context.getFactory(); 333 if (factory == null) { 334 throw new JXPathException( 335 "Factory is not set on the JXPathContext - cannot create path: " 336 + asPath()); 337 } 338 return factory; 339 } 340 341 public int compareChildNodePointers( 342 NodePointer pointer1, 343 NodePointer pointer2) 344 { 345 return pointer1.getIndex() - pointer2.getIndex(); 346 } 347 } | Popular Tags |