Coverage Report - org.apache.commons.ognl.ASTChain
 
Classes in this File Line Coverage Branch Coverage Complexity
ASTChain
83%
145/173
75%
132/176
8.538
 
 1  
 package org.apache.commons.ognl;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  * http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 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  
  * $Id: ASTChain.java 1197011 2011-11-03 09:19:44Z mcucchiara $
 30  
  * @author Luke Blanshard (blanshlu@netscape.net)
 31  
  * @author Drew Davidson (drew@ognl.org)
 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  
                      * System.out.println("astchain child: " + _children[i].getClass().getName() +
 298  
                      * " with current object target " + context.getCurrentObject() + " current type: " +
 299  
                      * context.getCurrentType());
 300  
                      */
 301  
 
 302  571
                     String value = child.toGetSourceString( context, context.getCurrentObject() );
 303  
 
 304  
                     // System.out.println("astchain child returned >>  " + value + "  <<");
 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  
                     // System.out.println("Astchain i: " + i + " currentobj : " + context.getCurrentObject() +
 317  
                     // " and root: " + context.getRoot());
 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  
                      * 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  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  
                     // System.out.println("astchain setsource child[" + i + "] : " + _children[i].getClass().getName());
 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  
                     // if (value == null || value.trim().length() <= 0)
 430  
                     // return "";
 431  
 
 432  
                     // System.out.println("astchain setter child returned >>  " + value + "  <<");
 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  
                     // 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  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  
 }