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 }