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