1 | |
package org.apache.commons.ognl; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
import org.apache.commons.ognl.enhance.ExpressionCompiler; |
23 | |
import org.apache.commons.ognl.enhance.OrderedReturn; |
24 | |
import org.apache.commons.ognl.enhance.UnsupportedCompilationException; |
25 | |
|
26 | |
import java.lang.reflect.Array; |
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | |
|
33 | |
public class ASTChain |
34 | |
extends SimpleNode |
35 | |
implements NodeType, OrderedReturn |
36 | |
{ |
37 | |
|
38 | |
private Class getterClass; |
39 | |
|
40 | |
private Class setterClass; |
41 | |
|
42 | |
private String lastExpression; |
43 | |
|
44 | |
private String coreExpression; |
45 | |
|
46 | |
public ASTChain( int id ) |
47 | |
{ |
48 | 610 | super( id ); |
49 | 610 | } |
50 | |
|
51 | |
public ASTChain( OgnlParser p, int id ) |
52 | |
{ |
53 | 0 | super( p, id ); |
54 | 0 | } |
55 | |
|
56 | |
public String getLastExpression() |
57 | |
{ |
58 | 112 | return lastExpression; |
59 | |
} |
60 | |
|
61 | |
public String getCoreExpression() |
62 | |
{ |
63 | 2 | return coreExpression; |
64 | |
} |
65 | |
|
66 | |
public void jjtClose() |
67 | |
{ |
68 | 609 | flattenTree(); |
69 | 609 | } |
70 | |
|
71 | |
protected Object getValueBody( OgnlContext context, Object source ) |
72 | |
throws OgnlException |
73 | |
{ |
74 | 217 | Object result = source; |
75 | |
|
76 | 682 | for ( int i = 0, ilast = children.length - 1; i <= ilast; ++i ) |
77 | |
{ |
78 | 477 | boolean handled = false; |
79 | |
|
80 | 477 | if ( i < ilast ) |
81 | |
{ |
82 | 276 | if ( children[i] instanceof ASTProperty ) |
83 | |
{ |
84 | 208 | ASTProperty propertyNode = (ASTProperty) children[i]; |
85 | 208 | int indexType = propertyNode.getIndexedPropertyType( context, result ); |
86 | |
|
87 | 208 | if ( ( indexType != OgnlRuntime.INDEXED_PROPERTY_NONE ) |
88 | |
&& ( children[i + 1] instanceof ASTProperty ) ) |
89 | |
{ |
90 | 17 | ASTProperty indexNode = (ASTProperty) children[i + 1]; |
91 | |
|
92 | 17 | if ( indexNode.isIndexedAccess() ) |
93 | |
{ |
94 | 17 | Object index = indexNode.getProperty( context, result ); |
95 | |
|
96 | 17 | if ( index instanceof DynamicSubscript ) |
97 | |
{ |
98 | 4 | if ( indexType == OgnlRuntime.INDEXED_PROPERTY_INT ) |
99 | |
{ |
100 | 3 | Object array = propertyNode.getValue( context, result ); |
101 | 3 | int len = Array.getLength( array ); |
102 | |
|
103 | 3 | switch ( ( (DynamicSubscript) index ).getFlag() ) |
104 | |
{ |
105 | |
case DynamicSubscript.ALL: |
106 | 0 | result = Array.newInstance( array.getClass().getComponentType(), len ); |
107 | 0 | System.arraycopy( array, 0, result, 0, len ); |
108 | 0 | handled = true; |
109 | 0 | i++; |
110 | 0 | break; |
111 | |
case DynamicSubscript.FIRST: |
112 | 1 | index = ( len > 0 ) ? 0 : -1; |
113 | 1 | break; |
114 | |
case DynamicSubscript.MID: |
115 | 1 | index = ( len > 0 ) ? ( len / 2 ) : -1; |
116 | 1 | break; |
117 | |
case DynamicSubscript.LAST: |
118 | 1 | index = ( len > 0 ) ? ( len - 1 ) : -1; |
119 | 1 | break; |
120 | |
default: |
121 | |
break; |
122 | |
} |
123 | 3 | } |
124 | |
else |
125 | |
{ |
126 | 1 | if ( indexType == OgnlRuntime.INDEXED_PROPERTY_OBJECT ) |
127 | |
{ |
128 | 1 | throw new OgnlException( "DynamicSubscript '" + indexNode |
129 | |
+ "' not allowed for object indexed property '" + propertyNode + "'" ); |
130 | |
} |
131 | |
} |
132 | |
} |
133 | 16 | if ( !handled ) |
134 | |
{ |
135 | 16 | result = |
136 | |
OgnlRuntime.getIndexedProperty( |
137 | |
context, |
138 | |
result, |
139 | |
propertyNode.getProperty( context, result ).toString(), |
140 | |
index ); |
141 | 13 | handled = true; |
142 | 13 | i++; |
143 | |
} |
144 | |
} |
145 | |
} |
146 | |
} |
147 | |
} |
148 | 473 | if ( !handled ) |
149 | |
{ |
150 | 460 | result = children[i].getValue( context, result ); |
151 | |
} |
152 | |
} |
153 | 205 | return result; |
154 | |
} |
155 | |
|
156 | |
protected void setValueBody( OgnlContext context, Object target, Object value ) |
157 | |
throws OgnlException |
158 | |
{ |
159 | 16 | boolean handled = false; |
160 | |
|
161 | 34 | for ( int i = 0, ilast = children.length - 2; i <= ilast; ++i ) |
162 | |
{ |
163 | 18 | if ( i <= ilast ) |
164 | |
{ |
165 | 18 | if ( children[i] instanceof ASTProperty ) |
166 | |
{ |
167 | 18 | ASTProperty propertyNode = (ASTProperty) children[i]; |
168 | 18 | int indexType = propertyNode.getIndexedPropertyType( context, target ); |
169 | |
|
170 | 18 | if ( ( indexType != OgnlRuntime.INDEXED_PROPERTY_NONE ) |
171 | |
&& ( children[i + 1] instanceof ASTProperty ) ) |
172 | |
{ |
173 | 2 | ASTProperty indexNode = (ASTProperty) children[i + 1]; |
174 | |
|
175 | 2 | if ( indexNode.isIndexedAccess() ) |
176 | |
{ |
177 | 2 | Object index = indexNode.getProperty( context, target ); |
178 | |
|
179 | 2 | if ( index instanceof DynamicSubscript ) |
180 | |
{ |
181 | 0 | if ( indexType == OgnlRuntime.INDEXED_PROPERTY_INT ) |
182 | |
{ |
183 | 0 | Object array = propertyNode.getValue( context, target ); |
184 | 0 | int len = Array.getLength( array ); |
185 | |
|
186 | 0 | switch ( ( (DynamicSubscript) index ).getFlag() ) |
187 | |
{ |
188 | |
case DynamicSubscript.ALL: |
189 | 0 | System.arraycopy( target, 0, value, 0, len ); |
190 | 0 | handled = true; |
191 | 0 | i++; |
192 | 0 | break; |
193 | |
case DynamicSubscript.FIRST: |
194 | 0 | index = ( len > 0 ) ? 0 : -1; |
195 | 0 | break; |
196 | |
case DynamicSubscript.MID: |
197 | 0 | index = ( len > 0 ) ? ( len / 2 ) : -1; |
198 | 0 | break; |
199 | |
case DynamicSubscript.LAST: |
200 | 0 | index = ( len > 0 ) ? ( len - 1 ) : -1; |
201 | 0 | break; |
202 | |
default: |
203 | |
break; |
204 | |
} |
205 | 0 | } |
206 | |
else |
207 | |
{ |
208 | 0 | if ( indexType == OgnlRuntime.INDEXED_PROPERTY_OBJECT ) |
209 | |
{ |
210 | 0 | throw new OgnlException( "DynamicSubscript '" + indexNode |
211 | |
+ "' not allowed for object indexed property '" + propertyNode + "'" ); |
212 | |
} |
213 | |
} |
214 | |
} |
215 | 2 | if ( !handled && i == ilast ) |
216 | |
{ |
217 | 1 | OgnlRuntime.setIndexedProperty( context, target, |
218 | |
propertyNode.getProperty( context, target ).toString(), |
219 | |
index, value ); |
220 | 1 | handled = true; |
221 | 1 | i++; |
222 | |
} |
223 | 1 | else if ( !handled ) |
224 | |
{ |
225 | 1 | target = |
226 | |
OgnlRuntime.getIndexedProperty( |
227 | |
context, |
228 | |
target, |
229 | |
propertyNode.getProperty( context, target ).toString(), |
230 | |
index ); |
231 | 1 | i++; |
232 | 1 | continue; |
233 | |
} |
234 | |
} |
235 | |
} |
236 | |
} |
237 | |
} |
238 | 17 | if ( !handled ) |
239 | |
{ |
240 | 16 | target = children[i].getValue( context, target ); |
241 | |
} |
242 | |
} |
243 | 16 | if ( !handled ) |
244 | |
{ |
245 | 15 | children[children.length - 1].setValue( context, target, value ); |
246 | |
} |
247 | 16 | } |
248 | |
|
249 | |
public boolean isSimpleNavigationChain( OgnlContext context ) |
250 | |
throws OgnlException |
251 | |
{ |
252 | 2 | boolean result = false; |
253 | |
|
254 | 2 | if ( ( children != null ) && ( children.length > 0 ) ) |
255 | |
{ |
256 | 2 | result = true; |
257 | 6 | for ( int i = 0; result && ( i < children.length ); i++ ) |
258 | |
{ |
259 | 4 | result = |
260 | |
children[i] instanceof SimpleNode && ( (SimpleNode) children[i] ).isSimpleProperty( context ); |
261 | |
} |
262 | |
} |
263 | 2 | return result; |
264 | |
} |
265 | |
|
266 | |
public Class getGetterClass() |
267 | |
{ |
268 | 76 | return getterClass; |
269 | |
} |
270 | |
|
271 | |
public Class getSetterClass() |
272 | |
{ |
273 | 0 | return setterClass; |
274 | |
} |
275 | |
|
276 | |
public String toGetSourceString( OgnlContext context, Object target ) |
277 | |
{ |
278 | 257 | String prevChain = (String) context.get( "_currentChain" ); |
279 | |
|
280 | 257 | if ( target != null ) |
281 | |
{ |
282 | 232 | context.setCurrentObject( target ); |
283 | 232 | context.setCurrentType( target.getClass() ); |
284 | |
} |
285 | |
|
286 | 257 | String result = ""; |
287 | 257 | NodeType lastType = null; |
288 | 257 | boolean ordered = false; |
289 | 257 | boolean constructor = false; |
290 | |
try |
291 | |
{ |
292 | 257 | if ( ( children != null ) && ( children.length > 0 ) ) |
293 | |
{ |
294 | 768 | for ( Node child : children ) |
295 | |
{ |
296 | |
|
297 | |
|
298 | |
|
299 | |
|
300 | |
|
301 | |
|
302 | 571 | String value = child.toGetSourceString( context, context.getCurrentObject() ); |
303 | |
|
304 | |
|
305 | |
|
306 | 511 | if ( ASTCtor.class.isInstance( child ) ) |
307 | |
{ |
308 | 3 | constructor = true; |
309 | |
} |
310 | |
|
311 | 511 | if ( NodeType.class.isInstance( child ) && ( (NodeType) child ).getGetterClass() != null ) |
312 | |
{ |
313 | 504 | lastType = (NodeType) child; |
314 | |
} |
315 | |
|
316 | |
|
317 | |
|
318 | 511 | if ( !ASTVarRef.class.isInstance( child ) && !constructor && !( |
319 | |
OrderedReturn.class.isInstance( child ) |
320 | |
&& ( (OrderedReturn) child ).getLastExpression() != null ) && ( parent == null |
321 | |
|| !ASTSequence.class.isInstance( parent ) ) ) |
322 | |
{ |
323 | 497 | value = OgnlRuntime.getCompiler( context ).castExpression( context, child, value ); |
324 | |
} |
325 | |
|
326 | |
|
327 | |
|
328 | |
|
329 | |
|
330 | |
|
331 | |
|
332 | 511 | if ( OrderedReturn.class.isInstance( child ) |
333 | |
&& ( (OrderedReturn) child ).getLastExpression() != null ) |
334 | |
{ |
335 | 1 | ordered = true; |
336 | 1 | OrderedReturn or = (OrderedReturn) child; |
337 | |
|
338 | 1 | if ( or.getCoreExpression() == null || or.getCoreExpression().trim().length() <= 0 ) |
339 | |
{ |
340 | 1 | result = ""; |
341 | |
} |
342 | |
else |
343 | |
{ |
344 | 0 | result += or.getCoreExpression(); |
345 | |
} |
346 | |
|
347 | 1 | lastExpression = or.getLastExpression(); |
348 | |
|
349 | 1 | if ( context.get( ExpressionCompiler.PRE_CAST ) != null ) |
350 | |
{ |
351 | 0 | lastExpression = context.remove( ExpressionCompiler.PRE_CAST ) + lastExpression; |
352 | |
} |
353 | 1 | } |
354 | 510 | else if ( ASTOr.class.isInstance( child ) || ASTAnd.class.isInstance( child ) |
355 | |
|| ASTCtor.class.isInstance( child ) || ( ASTStaticField.class.isInstance( child ) |
356 | |
&& parent == null ) ) |
357 | |
{ |
358 | 11 | context.put( "_noRoot", "true" ); |
359 | 11 | result = value; |
360 | |
} |
361 | |
else |
362 | |
{ |
363 | 499 | result += value; |
364 | |
} |
365 | |
|
366 | 511 | context.put( "_currentChain", result ); |
367 | |
} |
368 | |
} |
369 | |
} |
370 | 60 | catch ( Throwable t ) |
371 | |
{ |
372 | 60 | throw OgnlOps.castToRuntime( t ); |
373 | 197 | } |
374 | |
|
375 | 197 | if ( lastType != null ) |
376 | |
{ |
377 | 197 | getterClass = lastType.getGetterClass(); |
378 | 197 | setterClass = lastType.getSetterClass(); |
379 | |
} |
380 | |
|
381 | 197 | if ( ordered ) |
382 | |
{ |
383 | 1 | coreExpression = result; |
384 | |
} |
385 | |
|
386 | 197 | context.put( "_currentChain", prevChain ); |
387 | |
|
388 | 197 | return result; |
389 | |
} |
390 | |
|
391 | |
public String toSetSourceString( OgnlContext context, Object target ) |
392 | |
{ |
393 | 171 | String prevChain = (String) context.get( "_currentChain" ); |
394 | 171 | String prevChild = (String) context.get( "_lastChild" ); |
395 | |
|
396 | 171 | if ( prevChain != null ) |
397 | |
{ |
398 | 41 | throw new UnsupportedCompilationException( "Can't compile nested chain expressions." ); |
399 | |
} |
400 | |
|
401 | 130 | if ( target != null ) |
402 | |
{ |
403 | 107 | context.setCurrentObject( target ); |
404 | 107 | context.setCurrentType( target.getClass() ); |
405 | |
} |
406 | |
|
407 | 130 | String result = ""; |
408 | 130 | NodeType lastType = null; |
409 | 130 | boolean constructor = false; |
410 | |
try |
411 | |
{ |
412 | 130 | if ( ( children != null ) && ( children.length > 0 ) ) |
413 | |
{ |
414 | 130 | if ( ASTConst.class.isInstance( children[0] ) ) |
415 | |
{ |
416 | 3 | throw new UnsupportedCompilationException( "Can't modify constant values." ); |
417 | |
} |
418 | |
|
419 | 338 | for ( int i = 0; i < children.length; i++ ) |
420 | |
{ |
421 | |
|
422 | |
|
423 | 271 | if ( i == ( children.length - 1 ) ) |
424 | |
{ |
425 | 101 | context.put( "_lastChild", "true" ); |
426 | |
} |
427 | |
|
428 | 271 | String value = children[i].toSetSourceString( context, context.getCurrentObject() ); |
429 | |
|
430 | |
|
431 | |
|
432 | |
|
433 | |
|
434 | 211 | if ( ASTCtor.class.isInstance( children[i] ) ) |
435 | |
{ |
436 | 3 | constructor = true; |
437 | |
} |
438 | |
|
439 | 211 | if ( NodeType.class.isInstance( children[i] ) |
440 | |
&& ( (NodeType) children[i] ).getGetterClass() != null ) |
441 | |
{ |
442 | 206 | lastType = (NodeType) children[i]; |
443 | |
} |
444 | |
|
445 | 211 | if ( !ASTVarRef.class.isInstance( children[i] ) |
446 | |
&& !constructor |
447 | |
&& !( OrderedReturn.class.isInstance( children[i] ) |
448 | |
&& ( (OrderedReturn) children[i] ).getLastExpression() != null ) |
449 | |
&& ( parent == null || !ASTSequence.class.isInstance( parent ) ) ) |
450 | |
{ |
451 | 203 | value = OgnlRuntime.getCompiler( context ).castExpression( context, children[i], value ); |
452 | |
} |
453 | |
|
454 | |
|
455 | |
|
456 | |
|
457 | |
|
458 | |
|
459 | |
|
460 | |
|
461 | |
|
462 | 211 | if ( ASTOr.class.isInstance( children[i] ) || ASTAnd.class.isInstance( children[i] ) |
463 | |
|| ASTCtor.class.isInstance( children[i] ) || ASTStaticField.class.isInstance( children[i] ) ) |
464 | |
{ |
465 | 10 | context.put( "_noRoot", "true" ); |
466 | 10 | result = value; |
467 | |
} |
468 | |
else |
469 | |
{ |
470 | 201 | result += value; |
471 | |
} |
472 | |
|
473 | 211 | context.put( "_currentChain", result ); |
474 | |
} |
475 | |
} |
476 | |
} |
477 | 63 | catch ( Throwable t ) |
478 | |
{ |
479 | 63 | throw OgnlOps.castToRuntime( t ); |
480 | 67 | } |
481 | |
|
482 | 67 | context.put( "_lastChild", prevChild ); |
483 | 67 | context.put( "_currentChain", prevChain ); |
484 | |
|
485 | 67 | if ( lastType != null ) |
486 | |
{ |
487 | 67 | setterClass = lastType.getSetterClass(); |
488 | |
} |
489 | |
|
490 | 67 | return result; |
491 | |
} |
492 | |
|
493 | |
public <R, P> R accept( NodeVisitor<? extends R, ? super P> visitor, P data ) |
494 | |
throws OgnlException |
495 | |
{ |
496 | 0 | return visitor.visit( this, data ); |
497 | |
} |
498 | |
} |