Coverage Report - org.apache.commons.ognl.SimpleNode
 
Classes in this File Line Coverage Branch Coverage Complexity
SimpleNode
46%
67/145
40%
30/74
2.531
 
 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.ExpressionAccessor;
 23  
 
 24  
 import java.io.PrintWriter;
 25  
 import java.io.Serializable;
 26  
 
 27  
 /**
 28  
  * @author Luke Blanshard (blanshlu@netscape.net)
 29  
  * @author Drew Davidson (drew@ognl.org)
 30  
  */
 31  
 public abstract class SimpleNode
 32  
     implements Node, Serializable
 33  
 {
 34  
 
 35  
     private static final long serialVersionUID = 8305393337889433901L;
 36  
 
 37  
     protected Node parent;
 38  
 
 39  
     protected Node[] children;
 40  
 
 41  
     protected int id;
 42  
 
 43  
     protected OgnlParser parser;
 44  
 
 45  
     private boolean constantValueCalculated;
 46  
 
 47  
     private volatile boolean hasConstantValue;
 48  
 
 49  
     private Object constantValue;
 50  
 
 51  
     private ExpressionAccessor accessor;
 52  
 
 53  
     public SimpleNode( int i )
 54  5598
     {
 55  5598
         id = i;
 56  5598
     }
 57  
 
 58  
     public SimpleNode( OgnlParser p, int i )
 59  
     {
 60  0
         this( i );
 61  0
         parser = p;
 62  0
     }
 63  
 
 64  
     public void jjtOpen()
 65  
     {
 66  5580
     }
 67  
 
 68  
     public void jjtClose()
 69  
     {
 70  4667
     }
 71  
 
 72  
     public void jjtSetParent( Node n )
 73  
     {
 74  4443
         parent = n;
 75  4443
     }
 76  
 
 77  
     public Node jjtGetParent()
 78  
     {
 79  317
         return parent;
 80  
     }
 81  
 
 82  
     public void jjtAddChild( Node n, int i )
 83  
     {
 84  4446
         if ( children == null )
 85  
         {
 86  2921
             children = new Node[i + 1];
 87  
         }
 88  1525
         else if ( i >= children.length )
 89  
         {
 90  0
             Node c[] = new Node[i + 1];
 91  0
             System.arraycopy( children, 0, c, 0, children.length );
 92  0
             children = c;
 93  
         }
 94  4446
         children[i] = n;
 95  4446
     }
 96  
 
 97  
     public Node jjtGetChild( int i )
 98  
     {
 99  698
         return children[i];
 100  
     }
 101  
 
 102  
     public int jjtGetNumChildren()
 103  
     {
 104  1477
         return ( children == null ) ? 0 : children.length;
 105  
     }
 106  
 
 107  
     /*
 108  
      * You can override these two methods in subclasses of SimpleNode to customize the way the node appears when the
 109  
      * tree is dumped. If your output uses more than one line you should override toString(String), otherwise overriding
 110  
      * toString() is probably all you need to do.
 111  
      */
 112  
 
 113  
     @Override
 114  
     public String toString()
 115  
     {
 116  4
         final StringBuilder data = new StringBuilder();
 117  
         try
 118  
         {
 119  4
             accept( ToStringVisitor.INSTANCE, data );
 120  
         }
 121  0
         catch ( OgnlException e )
 122  
         {
 123  
             // ignored.
 124  4
         }
 125  4
         return data.toString();
 126  
     }
 127  
 
 128  
     // OGNL additions
 129  
 
 130  
     public String toString( String prefix )
 131  
     {
 132  0
         return prefix + OgnlParserTreeConstants.jjtNodeName[id] + " " + toString();
 133  
     }
 134  
 
 135  
     public String toGetSourceString( OgnlContext context, Object target )
 136  
     {
 137  0
         return toString();
 138  
     }
 139  
 
 140  
     public String toSetSourceString( OgnlContext context, Object target )
 141  
     {
 142  2
         return toString();
 143  
     }
 144  
 
 145  
     /*
 146  
      * Override this method if you want to customize how the node dumps out its children.
 147  
      */
 148  
 
 149  
     public void dump( PrintWriter writer, String prefix )
 150  
     {
 151  0
         writer.println( toString( prefix ) );
 152  
 
 153  0
         if ( children != null )
 154  
         {
 155  0
             for ( int i = 0; i < children.length; ++i )
 156  
             {
 157  0
                 SimpleNode n = (SimpleNode) children[i];
 158  0
                 if ( n != null )
 159  
                 {
 160  0
                     n.dump( writer, prefix + "  " );
 161  
                 }
 162  
             }
 163  
         }
 164  0
     }
 165  
 
 166  
     public int getIndexInParent()
 167  
     {
 168  0
         int result = -1;
 169  
 
 170  0
         if ( parent != null )
 171  
         {
 172  0
             int icount = parent.jjtGetNumChildren();
 173  
 
 174  0
             for ( int i = 0; i < icount; i++ )
 175  
             {
 176  0
                 if ( parent.jjtGetChild( i ) == this )
 177  
                 {
 178  0
                     result = i;
 179  0
                     break;
 180  
                 }
 181  
             }
 182  
         }
 183  
 
 184  0
         return result;
 185  
     }
 186  
 
 187  
     public Node getNextSibling()
 188  
     {
 189  0
         Node result = null;
 190  0
         int i = getIndexInParent();
 191  
 
 192  0
         if ( i >= 0 )
 193  
         {
 194  0
             int icount = parent.jjtGetNumChildren();
 195  
 
 196  0
             if ( i < icount )
 197  
             {
 198  0
                 result = parent.jjtGetChild( i + 1 );
 199  
             }
 200  
         }
 201  0
         return result;
 202  
     }
 203  
 
 204  
     protected Object evaluateGetValueBody( OgnlContext context, Object source )
 205  
         throws OgnlException
 206  
     {
 207  7342
         context.setCurrentObject( source );
 208  7342
         context.setCurrentNode( this );
 209  
 
 210  7342
         if ( !constantValueCalculated )
 211  
         {
 212  2171
             constantValueCalculated = true;
 213  2171
             boolean constant = isConstant( context );
 214  
 
 215  2171
             if ( constant )
 216  
             {
 217  1198
                 constantValue = getValueBody( context, source );
 218  
             }
 219  
 
 220  2171
             hasConstantValue = constant;
 221  
         }
 222  
 
 223  7342
         return hasConstantValue ? constantValue : getValueBody( context, source );
 224  
     }
 225  
 
 226  
     protected void evaluateSetValueBody( OgnlContext context, Object target, Object value )
 227  
         throws OgnlException
 228  
     {
 229  94
         context.setCurrentObject( target );
 230  94
         context.setCurrentNode( this );
 231  94
         setValueBody( context, target, value );
 232  93
     }
 233  
 
 234  
     public final Object getValue( OgnlContext context, Object source )
 235  
         throws OgnlException
 236  
     {
 237  7342
         Object result = null;
 238  
 
 239  7342
         if ( context.getTraceEvaluations() )
 240  
         {
 241  
 
 242  0
             EvaluationPool pool = OgnlRuntime.getEvaluationPool();
 243  0
             Throwable evalException = null;
 244  0
             Evaluation evaluation = pool.create( this, source );
 245  
 
 246  0
             context.pushEvaluation( evaluation );
 247  
             try
 248  
             {
 249  0
                 result = evaluateGetValueBody( context, source );
 250  
             }
 251  0
             catch ( OgnlException ex )
 252  
             {
 253  0
                 evalException = ex;
 254  0
                 throw ex;
 255  
             }
 256  0
             catch ( RuntimeException ex )
 257  
             {
 258  0
                 evalException = ex;
 259  0
                 throw ex;
 260  
             }
 261  
             finally
 262  
             {
 263  0
                 Evaluation eval = context.popEvaluation();
 264  
 
 265  0
                 eval.setResult( result );
 266  0
                 if ( evalException != null )
 267  
                 {
 268  0
                     eval.setException( evalException );
 269  
                 }
 270  0
                 if ( ( evalException == null ) && ( context.getRootEvaluation() == null )
 271  
                     && !context.getKeepLastEvaluation() )
 272  
                 {
 273  0
                     pool.recycleAll( eval );
 274  
                 }
 275  0
             }
 276  0
         }
 277  
         else
 278  
         {
 279  7342
             result = evaluateGetValueBody( context, source );
 280  
         }
 281  
 
 282  7212
         return result;
 283  
     }
 284  
 
 285  
     /**
 286  
      * Subclasses implement this method to do the actual work of extracting the appropriate value from the source
 287  
      * object.
 288  
      */
 289  
     protected abstract Object getValueBody( OgnlContext context, Object source )
 290  
         throws OgnlException;
 291  
 
 292  
     public final void setValue( OgnlContext context, Object target, Object value )
 293  
         throws OgnlException
 294  
     {
 295  94
         if ( context.getTraceEvaluations() )
 296  
         {
 297  0
             EvaluationPool pool = OgnlRuntime.getEvaluationPool();
 298  0
             Throwable evalException = null;
 299  0
             Evaluation evaluation = pool.create( this, target, true );
 300  
 
 301  0
             context.pushEvaluation( evaluation );
 302  
             try
 303  
             {
 304  0
                 evaluateSetValueBody( context, target, value );
 305  
             }
 306  0
             catch ( OgnlException ex )
 307  
             {
 308  0
                 evalException = ex;
 309  0
                 ex.setEvaluation( evaluation );
 310  0
                 throw ex;
 311  
             }
 312  0
             catch ( RuntimeException ex )
 313  
             {
 314  0
                 evalException = ex;
 315  0
                 throw ex;
 316  
             }
 317  
             finally
 318  
             {
 319  0
                 Evaluation eval = context.popEvaluation();
 320  
 
 321  0
                 if ( evalException != null )
 322  
                 {
 323  0
                     eval.setException( evalException );
 324  
                 }
 325  0
                 if ( ( evalException == null ) && ( context.getRootEvaluation() == null )
 326  
                     && !context.getKeepLastEvaluation() )
 327  
                 {
 328  0
                     pool.recycleAll( eval );
 329  
                 }
 330  0
             }
 331  0
         }
 332  
         else
 333  
         {
 334  94
             evaluateSetValueBody( context, target, value );
 335  
         }
 336  93
     }
 337  
 
 338  
     /**
 339  
      * Subclasses implement this method to do the actual work of setting the appropriate value in the target object. The
 340  
      * default implementation throws an <code>InappropriateExpressionException</code>, meaning that it cannot be a set
 341  
      * expression.
 342  
      */
 343  
     protected void setValueBody( OgnlContext context, Object target, Object value )
 344  
         throws OgnlException
 345  
     {
 346  0
         throw new InappropriateExpressionException( this );
 347  
     }
 348  
 
 349  
     /** Returns true iff this node is constant without respect to the children. */
 350  
     public boolean isNodeConstant( OgnlContext context )
 351  
         throws OgnlException
 352  
     {
 353  979
         return false;
 354  
     }
 355  
 
 356  
     public boolean isConstant( OgnlContext context )
 357  
         throws OgnlException
 358  
     {
 359  2278
         return isNodeConstant( context );
 360  
     }
 361  
 
 362  
     public boolean isNodeSimpleProperty( OgnlContext context )
 363  
         throws OgnlException
 364  
     {
 365  13
         return false;
 366  
     }
 367  
 
 368  
     public boolean isSimpleProperty( OgnlContext context )
 369  
         throws OgnlException
 370  
     {
 371  22
         return isNodeSimpleProperty( context );
 372  
     }
 373  
 
 374  
     public boolean isSimpleNavigationChain( OgnlContext context )
 375  
         throws OgnlException
 376  
     {
 377  2
         return isSimpleProperty( context );
 378  
     }
 379  
 
 380  
     public boolean isEvalChain( OgnlContext context )
 381  
         throws OgnlException
 382  
     {
 383  0
         if ( children == null )
 384  
         {
 385  0
             return false;
 386  
         }
 387  0
         for ( Node child : children )
 388  
         {
 389  0
             if ( child instanceof SimpleNode )
 390  
             {
 391  0
                 if ( ( (SimpleNode) child ).isEvalChain( context ) )
 392  
                 {
 393  0
                     return true;
 394  
                 }
 395  
             }
 396  
         }
 397  0
         return false;
 398  
     }
 399  
 
 400  
     protected boolean lastChild( OgnlContext context )
 401  
     {
 402  449
         return parent == null || context.get( "_lastChild" ) != null;
 403  
     }
 404  
 
 405  
     /**
 406  
      * This method may be called from subclasses' jjtClose methods. It flattens the tree under this node by eliminating
 407  
      * any children that are of the same class as this node and copying their children to this node.
 408  
      */
 409  
     protected void flattenTree()
 410  
     {
 411  913
         boolean shouldFlatten = false;
 412  913
         int newSize = 0;
 413  
 
 414  2739
         for ( Node aChildren : children )
 415  
         {
 416  1826
             if ( aChildren.getClass() == getClass() )
 417  
             {
 418  191
                 shouldFlatten = true;
 419  191
                 newSize += aChildren.jjtGetNumChildren();
 420  
             }
 421  
             else
 422  
             {
 423  1635
                 ++newSize;
 424  
             }
 425  
         }
 426  
 
 427  913
         if ( shouldFlatten )
 428  
         {
 429  191
             Node[] newChildren = new Node[newSize];
 430  191
             int j = 0;
 431  
 
 432  573
             for ( Node c : children )
 433  
             {
 434  382
                 if ( c.getClass() == getClass() )
 435  
                 {
 436  616
                     for ( int k = 0; k < c.jjtGetNumChildren(); ++k )
 437  
                     {
 438  425
                         newChildren[j++] = c.jjtGetChild( k );
 439  
                     }
 440  
 
 441  
                 }
 442  
                 else
 443  
                 {
 444  191
                     newChildren[j++] = c;
 445  
                 }
 446  
             }
 447  
 
 448  191
             if ( j != newSize )
 449  
             {
 450  0
                 throw new Error( "Assertion error: " + j + " != " + newSize );
 451  
             }
 452  
 
 453  191
             children = newChildren;
 454  
         }
 455  913
     }
 456  
 
 457  
     public ExpressionAccessor getAccessor()
 458  
     {
 459  2313
         return accessor;
 460  
     }
 461  
 
 462  
     public void setAccessor( ExpressionAccessor accessor )
 463  
     {
 464  567
         this.accessor = accessor;
 465  567
     }
 466  
 }