001 package org.apache.commons.ognl;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import org.apache.commons.ognl.enhance.ExpressionCompiler;
023 import org.apache.commons.ognl.enhance.OrderedReturn;
024 import org.apache.commons.ognl.enhance.UnsupportedCompilationException;
025
026 import java.lang.reflect.Array;
027
028 /**
029 * $Id: ASTChain.java 1197011 2011-11-03 09:19:44Z mcucchiara $
030 * @author Luke Blanshard (blanshlu@netscape.net)
031 * @author Drew Davidson (drew@ognl.org)
032 */
033 public class ASTChain
034 extends SimpleNode
035 implements NodeType, OrderedReturn
036 {
037
038 private Class getterClass;
039
040 private Class setterClass;
041
042 private String lastExpression;
043
044 private String coreExpression;
045
046 public ASTChain( int id )
047 {
048 super( id );
049 }
050
051 public ASTChain( OgnlParser p, int id )
052 {
053 super( p, id );
054 }
055
056 public String getLastExpression()
057 {
058 return lastExpression;
059 }
060
061 public String getCoreExpression()
062 {
063 return coreExpression;
064 }
065
066 public void jjtClose()
067 {
068 flattenTree();
069 }
070
071 protected Object getValueBody( OgnlContext context, Object source )
072 throws OgnlException
073 {
074 Object result = source;
075
076 for ( int i = 0, ilast = children.length - 1; i <= ilast; ++i )
077 {
078 boolean handled = false;
079
080 if ( i < ilast )
081 {
082 if ( children[i] instanceof ASTProperty )
083 {
084 ASTProperty propertyNode = (ASTProperty) children[i];
085 int indexType = propertyNode.getIndexedPropertyType( context, result );
086
087 if ( ( indexType != OgnlRuntime.INDEXED_PROPERTY_NONE )
088 && ( children[i + 1] instanceof ASTProperty ) )
089 {
090 ASTProperty indexNode = (ASTProperty) children[i + 1];
091
092 if ( indexNode.isIndexedAccess() )
093 {
094 Object index = indexNode.getProperty( context, result );
095
096 if ( index instanceof DynamicSubscript )
097 {
098 if ( indexType == OgnlRuntime.INDEXED_PROPERTY_INT )
099 {
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 * System.out.println("astchain child: " + _children[i].getClass().getName() +
298 * " with current object target " + context.getCurrentObject() + " current type: " +
299 * context.getCurrentType());
300 */
301
302 String value = child.toGetSourceString( context, context.getCurrentObject() );
303
304 // System.out.println("astchain child returned >> " + value + " <<");
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 // System.out.println("Astchain i: " + i + " currentobj : " + context.getCurrentObject() +
317 // " and root: " + context.getRoot());
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 * System.out.println("astchain value now : " + value + " with index " + i + " current type " +
328 * context.getCurrentType() + " current accessor " + context.getCurrentAccessor() + " prev type " +
329 * context.getPreviousType() + " prev accessor " + context.getPreviousAccessor());
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 // System.out.println("astchain setsource child[" + i + "] : " + _children[i].getClass().getName());
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 // if (value == null || value.trim().length() <= 0)
430 // return "";
431
432 // System.out.println("astchain setter child returned >> " + value + " <<");
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 // System.out.println("astchain setter after cast value is: " + value);
455
456 /*
457 * if (!constructor && !OrderedReturn.class.isInstance(_children[i]) && (_parent == null ||
458 * !ASTSequence.class.isInstance(_parent))) { value =
459 * OgnlRuntime.getCompiler().castExpression(context, _children[i], value); }
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 }