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