Coverage Report - org.apache.commons.ognl.OgnlContext
 
Classes in this File Line Coverage Branch Coverage Complexity
OgnlContext
48%
126/259
22%
27/120
2.276
 
 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.LocalReference;
 23  
 
 24  
 import java.util.Collection;
 25  
 import java.util.HashMap;
 26  
 import java.util.HashSet;
 27  
 import java.util.LinkedHashMap;
 28  
 import java.util.Map;
 29  
 import java.util.Set;
 30  
 import java.util.Stack;
 31  
 
 32  
 /**
 33  
  * This class defines the execution context for an OGNL expression
 34  
  * 
 35  
  * @author Luke Blanshard (blanshlu@netscape.net)
 36  
  * @author Drew Davidson (drew@ognl.org)
 37  
  */
 38  0
 public class OgnlContext
 39  
     implements Map<String, Object>
 40  
 {
 41  
 
 42  
     public static final String CONTEXT_CONTEXT_KEY = "context";
 43  
 
 44  
     public static final String ROOT_CONTEXT_KEY = "root";
 45  
 
 46  
     public static final String THIS_CONTEXT_KEY = "this";
 47  
 
 48  
     public static final String TRACE_EVALUATIONS_CONTEXT_KEY = "_traceEvaluations";
 49  
 
 50  
     public static final String LAST_EVALUATION_CONTEXT_KEY = "_lastEvaluation";
 51  
 
 52  
     public static final String KEEP_LAST_EVALUATION_CONTEXT_KEY = "_keepLastEvaluation";
 53  
 
 54  
     public static final String CLASS_RESOLVER_CONTEXT_KEY = "_classResolver";
 55  
 
 56  
     public static final String TYPE_CONVERTER_CONTEXT_KEY = "_typeConverter";
 57  
 
 58  
     public static final String MEMBER_ACCESS_CONTEXT_KEY = "_memberAccess";
 59  
 
 60  
     private static final String PROPERTY_KEY_PREFIX = "ognl";
 61  
 
 62  1
     private static boolean defaultTraceEvaluations = false;
 63  
 
 64  1
     private static boolean defaultKeepLastEvaluation = false;
 65  
 
 66  1
     public static final DefaultClassResolver DEFAULT_CLASS_RESOLVER = new DefaultClassResolver();
 67  
 
 68  1
     public static final TypeConverter DEFAULT_TYPE_CONVERTER = new DefaultTypeConverter();
 69  
 
 70  1
     public static final MemberAccess DEFAULT_MEMBER_ACCESS = new DefaultMemberAccess( false );
 71  
 
 72  1
     private static final Set<String> RESERVED_KEYS = new HashSet<String>( 11 );
 73  
 
 74  
     private Object root;
 75  
 
 76  
     private Object currentObject;
 77  
 
 78  
     private Node currentNode;
 79  
 
 80  722
     private boolean traceEvaluations = defaultTraceEvaluations;
 81  
 
 82  
     private Evaluation rootEvaluation;
 83  
 
 84  
     private Evaluation currentEvaluation;
 85  
 
 86  
     private Evaluation lastEvaluation;
 87  
 
 88  722
     private boolean keepLastEvaluation = defaultKeepLastEvaluation;
 89  
 
 90  722
     private Map<String, Object> values = new HashMap<String, Object>( 23 );
 91  
 
 92  722
     private ClassResolver classResolver = DEFAULT_CLASS_RESOLVER;
 93  
 
 94  722
     private TypeConverter typeConverter = DEFAULT_TYPE_CONVERTER;
 95  
 
 96  722
     private MemberAccess memberAccess = DEFAULT_MEMBER_ACCESS;
 97  
 
 98  
     static
 99  
     {
 100  
         String s;
 101  
 
 102  1
         RESERVED_KEYS.add( CONTEXT_CONTEXT_KEY );
 103  1
         RESERVED_KEYS.add( ROOT_CONTEXT_KEY );
 104  1
         RESERVED_KEYS.add( THIS_CONTEXT_KEY );
 105  1
         RESERVED_KEYS.add( TRACE_EVALUATIONS_CONTEXT_KEY );
 106  1
         RESERVED_KEYS.add( LAST_EVALUATION_CONTEXT_KEY );
 107  1
         RESERVED_KEYS.add( KEEP_LAST_EVALUATION_CONTEXT_KEY );
 108  1
         RESERVED_KEYS.add( CLASS_RESOLVER_CONTEXT_KEY );
 109  1
         RESERVED_KEYS.add( TYPE_CONVERTER_CONTEXT_KEY );
 110  1
         RESERVED_KEYS.add( MEMBER_ACCESS_CONTEXT_KEY );
 111  
 
 112  
         try
 113  
         {
 114  1
             s = System.getProperty( PROPERTY_KEY_PREFIX + ".traceEvaluations" );
 115  1
             if ( s != null )
 116  
             {
 117  0
                 defaultTraceEvaluations = Boolean.valueOf( s.trim() );
 118  
             }
 119  1
             s = System.getProperty( PROPERTY_KEY_PREFIX + ".keepLastEvaluation" );
 120  1
             if ( s != null )
 121  
             {
 122  0
                 defaultKeepLastEvaluation = Boolean.valueOf( s.trim() );
 123  
             }
 124  
         }
 125  0
         catch ( SecurityException ex )
 126  
         {
 127  
             // restricted access environment, just keep defaults
 128  1
         }
 129  1
     }
 130  
 
 131  722
     private Stack<Class<?>> typeStack = new Stack<Class<?>>();
 132  
 
 133  722
     private Stack<Class<?>> accessorStack = new Stack<Class<?>>();
 134  
 
 135  722
     private int localReferenceCounter = 0;
 136  
 
 137  722
     private Map<String, LocalReference> localReferenceMap = null;
 138  
 
 139  
     /**
 140  
      * Constructs a new OgnlContext with the default class resolver, type converter and member access.
 141  
      */
 142  
     public OgnlContext()
 143  722
     {
 144  722
     }
 145  
 
 146  
     /**
 147  
      * Constructs a new OgnlContext with the given class resolver, type converter and member access. If any of these
 148  
      * parameters is null the default will be used.
 149  
      */
 150  
     public OgnlContext( ClassResolver classResolver, TypeConverter typeConverter, MemberAccess memberAccess )
 151  
     {
 152  0
         this();
 153  0
         if ( classResolver != null )
 154  
         {
 155  0
             this.classResolver = classResolver;
 156  
         }
 157  0
         if ( typeConverter != null )
 158  
         {
 159  0
             this.typeConverter = typeConverter;
 160  
         }
 161  0
         if ( memberAccess != null )
 162  
         {
 163  0
             this.memberAccess = memberAccess;
 164  
         }
 165  0
     }
 166  
 
 167  
     public OgnlContext( Map<String, Object> values )
 168  
     {
 169  0
         super();
 170  0
         this.values = values;
 171  0
     }
 172  
 
 173  
     public OgnlContext( ClassResolver classResolver, TypeConverter typeConverter, MemberAccess memberAccess,
 174  
                         Map<String, Object> values )
 175  
     {
 176  0
         this( classResolver, typeConverter, memberAccess );
 177  0
         this.values = values;
 178  0
     }
 179  
 
 180  
     public void setValues( Map<String, Object> value )
 181  
     {
 182  0
         values.putAll( value );
 183  0
     }
 184  
 
 185  
     public Map<String, Object> getValues()
 186  
     {
 187  0
         return values;
 188  
     }
 189  
 
 190  
     public void setClassResolver( ClassResolver value )
 191  
     {
 192  4
         if ( value == null )
 193  
         {
 194  0
             throw new IllegalArgumentException( "cannot set ClassResolver to null" );
 195  
         }
 196  4
         classResolver = value;
 197  4
     }
 198  
 
 199  
     public ClassResolver getClassResolver()
 200  
     {
 201  873
         return classResolver;
 202  
     }
 203  
 
 204  
     public void setTypeConverter( TypeConverter value )
 205  
     {
 206  4
         if ( value == null )
 207  
         {
 208  0
             throw new IllegalArgumentException( "cannot set TypeConverter to null" );
 209  
         }
 210  4
         typeConverter = value;
 211  4
     }
 212  
 
 213  
     public TypeConverter getTypeConverter()
 214  
     {
 215  61
         return typeConverter;
 216  
     }
 217  
 
 218  
     public void setMemberAccess( MemberAccess value )
 219  
     {
 220  21
         if ( value == null )
 221  
         {
 222  0
             throw new IllegalArgumentException( "cannot set MemberAccess to null" );
 223  
         }
 224  21
         memberAccess = value;
 225  21
     }
 226  
 
 227  
     public MemberAccess getMemberAccess()
 228  
     {
 229  2226
         return memberAccess;
 230  
     }
 231  
 
 232  
     public void setRoot( Object value )
 233  
     {
 234  2527
         root = value;
 235  2527
         accessorStack.clear();
 236  2527
         typeStack.clear();
 237  2527
         currentObject = value;
 238  
 
 239  2527
         if ( currentObject != null )
 240  
         {
 241  1313
             setCurrentType( currentObject.getClass() );
 242  
         }
 243  2527
     }
 244  
 
 245  
     public Object getRoot()
 246  
     {
 247  7084
         return root;
 248  
     }
 249  
 
 250  
     public boolean getTraceEvaluations()
 251  
     {
 252  7436
         return traceEvaluations;
 253  
     }
 254  
 
 255  
     public void setTraceEvaluations( boolean value )
 256  
     {
 257  0
         traceEvaluations = value;
 258  0
     }
 259  
 
 260  
     public Evaluation getLastEvaluation()
 261  
     {
 262  0
         return lastEvaluation;
 263  
     }
 264  
 
 265  
     public void setLastEvaluation( Evaluation value )
 266  
     {
 267  4
         lastEvaluation = value;
 268  4
     }
 269  
 
 270  
     /**
 271  
      * This method can be called when the last evaluation has been used and can be returned for reuse in the free pool
 272  
      * maintained by the runtime. This is not a necessary step, but is useful for keeping memory usage down. This will
 273  
      * recycle the last evaluation and then set the last evaluation to null.
 274  
      */
 275  
     public void recycleLastEvaluation()
 276  
     {
 277  0
         OgnlRuntime.getEvaluationPool().recycleAll( lastEvaluation );
 278  0
         lastEvaluation = null;
 279  0
     }
 280  
 
 281  
     /**
 282  
      * Returns true if the last evaluation that was done on this context is retained and available through
 283  
      * <code>getLastEvaluation()</code>. The default is true.
 284  
      */
 285  
     public boolean getKeepLastEvaluation()
 286  
     {
 287  0
         return keepLastEvaluation;
 288  
     }
 289  
 
 290  
     /**
 291  
      * Sets whether the last evaluation that was done on this context is retained and available through
 292  
      * <code>getLastEvaluation()</code>. The default is true.
 293  
      */
 294  
     public void setKeepLastEvaluation( boolean value )
 295  
     {
 296  0
         keepLastEvaluation = value;
 297  0
     }
 298  
 
 299  
     public void setCurrentObject( Object value )
 300  
     {
 301  12346
         currentObject = value;
 302  12346
     }
 303  
 
 304  
     public Object getCurrentObject()
 305  
     {
 306  9415
         return currentObject;
 307  
     }
 308  
 
 309  
     public void setCurrentAccessor( Class<?> type )
 310  
     {
 311  1910
         accessorStack.add( type );
 312  1910
     }
 313  
 
 314  
     public Class<?> getCurrentAccessor()
 315  
     {
 316  2008
         if ( accessorStack.isEmpty() )
 317  
         {
 318  92
             return null;
 319  
         }
 320  
 
 321  1916
         return accessorStack.peek();
 322  
     }
 323  
 
 324  
     public Class<?> getPreviousAccessor()
 325  
     {
 326  13
         if ( accessorStack.isEmpty() )
 327  
         {
 328  4
             return null;
 329  
         }
 330  
 
 331  9
         if ( accessorStack.size() > 1 )
 332  
         {
 333  2
             return accessorStack.get( accessorStack.size() - 2 );
 334  
         }
 335  
 
 336  7
         return null;
 337  
     }
 338  
 
 339  
     public Class<?> getFirstAccessor()
 340  
     {
 341  1442
         if ( accessorStack.isEmpty() )
 342  
         {
 343  1
             return null;
 344  
         }
 345  
 
 346  1441
         return accessorStack.get( 0 );
 347  
     }
 348  
 
 349  
     /**
 350  
      * Gets the current class type being evaluated on the stack, as set by {@link #setCurrentType(Class)}.
 351  
      * 
 352  
      * @return The current object type, may be null.
 353  
      */
 354  
     public Class<?> getCurrentType()
 355  
     {
 356  5135
         if ( typeStack.isEmpty() )
 357  
         {
 358  22
             return null;
 359  
         }
 360  
 
 361  5113
         return typeStack.peek();
 362  
     }
 363  
 
 364  
     public void setCurrentType( Class<?> type )
 365  
     {
 366  5154
         typeStack.add( type );
 367  5154
     }
 368  
 
 369  
     /**
 370  
      * Represents the last known object type on the evaluation stack, will be the value of the last known
 371  
      * {@link #getCurrentType()}.
 372  
      * 
 373  
      * @return The previous type of object on the stack, may be null.
 374  
      */
 375  
     public Class<?> getPreviousType()
 376  
     {
 377  2590
         if ( typeStack.isEmpty() )
 378  
         {
 379  0
             return null;
 380  
         }
 381  
 
 382  2590
         if ( typeStack.size() > 1 )
 383  
         {
 384  2354
             return typeStack.get( typeStack.size() - 2 );
 385  
         }
 386  
 
 387  236
         return null;
 388  
     }
 389  
 
 390  
     public void setPreviousType( Class<?> type )
 391  
     {
 392  1216
         if ( typeStack.isEmpty() || typeStack.size() < 2 )
 393  
         {
 394  0
             return;
 395  
         }
 396  
 
 397  1216
         typeStack.set( typeStack.size() - 2, type );
 398  1216
     }
 399  
 
 400  
     public Class<?> getFirstType()
 401  
     {
 402  0
         if ( typeStack.isEmpty() )
 403  
         {
 404  0
             return null;
 405  
         }
 406  
 
 407  0
         return typeStack.get( 0 );
 408  
     }
 409  
 
 410  
     public void setCurrentNode( Node value )
 411  
     {
 412  7446
         currentNode = value;
 413  7446
     }
 414  
 
 415  
     public Node getCurrentNode()
 416  
     {
 417  310
         return currentNode;
 418  
     }
 419  
 
 420  
     /**
 421  
      * Gets the current Evaluation from the top of the stack. This is the Evaluation that is in process of evaluating.
 422  
      */
 423  
     public Evaluation getCurrentEvaluation()
 424  
     {
 425  0
         return currentEvaluation;
 426  
     }
 427  
 
 428  
     public void setCurrentEvaluation( Evaluation value )
 429  
     {
 430  4
         currentEvaluation = value;
 431  4
     }
 432  
 
 433  
     /**
 434  
      * Gets the root of the evaluation stack. This Evaluation contains the node representing the root expression and the
 435  
      * source is the root source object.
 436  
      */
 437  
     public Evaluation getRootEvaluation()
 438  
     {
 439  0
         return rootEvaluation;
 440  
     }
 441  
 
 442  
     public void setRootEvaluation( Evaluation value )
 443  
     {
 444  4
         rootEvaluation = value;
 445  4
     }
 446  
 
 447  
     /**
 448  
      * Returns the Evaluation at the relative index given. This should be zero or a negative number as a relative
 449  
      * reference back up the evaluation stack. Therefore getEvaluation(0) returns the current Evaluation.
 450  
      */
 451  
     public Evaluation getEvaluation( int relativeIndex )
 452  
     {
 453  0
         Evaluation result = null;
 454  
 
 455  0
         if ( relativeIndex <= 0 )
 456  
         {
 457  0
             result = currentEvaluation;
 458  0
             while ( ( ++relativeIndex < 0 ) && ( result != null ) )
 459  
             {
 460  0
                 result = result.getParent();
 461  
             }
 462  
         }
 463  0
         return result;
 464  
     }
 465  
 
 466  
     /**
 467  
      * Pushes a new Evaluation onto the stack. This is done before a node evaluates. When evaluation is complete it
 468  
      * should be popped from the stack via <code>popEvaluation()</code>.
 469  
      */
 470  
     public void pushEvaluation( Evaluation value )
 471  
     {
 472  0
         if ( currentEvaluation != null )
 473  
         {
 474  0
             currentEvaluation.addChild( value );
 475  
         }
 476  
         else
 477  
         {
 478  0
             setRootEvaluation( value );
 479  
         }
 480  0
         setCurrentEvaluation( value );
 481  0
     }
 482  
 
 483  
     /**
 484  
      * Pops the current Evaluation off of the top of the stack. This is done after a node has completed its evaluation.
 485  
      */
 486  
     public Evaluation popEvaluation()
 487  
     {
 488  
         Evaluation result;
 489  
 
 490  0
         result = currentEvaluation;
 491  0
         setCurrentEvaluation( result.getParent() );
 492  0
         if ( currentEvaluation == null )
 493  
         {
 494  0
             setLastEvaluation( getKeepLastEvaluation() ? result : null );
 495  0
             setRootEvaluation( null );
 496  0
             setCurrentNode( null );
 497  
         }
 498  0
         return result;
 499  
     }
 500  
 
 501  
     public int incrementLocalReferenceCounter()
 502  
     {
 503  149
         return ++localReferenceCounter;
 504  
     }
 505  
 
 506  
     public void addLocalReference( String key, LocalReference reference )
 507  
     {
 508  149
         if ( localReferenceMap == null )
 509  
         {
 510  88
             localReferenceMap = new LinkedHashMap<String, LocalReference>();
 511  
         }
 512  
 
 513  149
         localReferenceMap.put( key, reference );
 514  149
     }
 515  
 
 516  
     public Map<String, LocalReference> getLocalReferences()
 517  
     {
 518  541
         return localReferenceMap;
 519  
     }
 520  
 
 521  
     /* ================= Map interface ================= */
 522  
     public int size()
 523  
     {
 524  0
         return values.size();
 525  
     }
 526  
 
 527  
     public boolean isEmpty()
 528  
     {
 529  0
         return values.isEmpty();
 530  
     }
 531  
 
 532  
     public boolean containsKey( Object key )
 533  
     {
 534  0
         return values.containsKey( key );
 535  
     }
 536  
 
 537  
     public boolean containsValue( Object value )
 538  
     {
 539  0
         return values.containsValue( value );
 540  
     }
 541  
 
 542  
     public Object get( Object key )
 543  
     {
 544  2886
         Object result = null;
 545  
 
 546  
         // FIXME: complexity is O(n)
 547  2886
         if ( RESERVED_KEYS.contains( key ) )
 548  
         {
 549  0
             if ( THIS_CONTEXT_KEY.equals( key ) )
 550  
             {
 551  0
                 result = getCurrentObject();
 552  
             }
 553  0
             else if ( ROOT_CONTEXT_KEY.equals( key ) )
 554  
             {
 555  0
                 result = getRoot();
 556  
             }
 557  0
             else if ( CONTEXT_CONTEXT_KEY.equals( key ) )
 558  
             {
 559  0
                 result = this;
 560  
             }
 561  0
             else if ( TRACE_EVALUATIONS_CONTEXT_KEY.equals( key ) )
 562  
             {
 563  0
                 result = getTraceEvaluations() ? Boolean.TRUE : Boolean.FALSE;
 564  
             }
 565  0
             else if ( LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
 566  
             {
 567  0
                 result = getLastEvaluation();
 568  
             }
 569  0
             else if ( KEEP_LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
 570  
             {
 571  0
                 result = getKeepLastEvaluation() ? Boolean.TRUE : Boolean.FALSE;
 572  
             }
 573  0
             else if ( CLASS_RESOLVER_CONTEXT_KEY.equals( key ) )
 574  
             {
 575  0
                 result = getClassResolver();
 576  
             }
 577  0
             else if ( TYPE_CONVERTER_CONTEXT_KEY.equals( key ) )
 578  
             {
 579  0
                 result = getTypeConverter();
 580  
             }
 581  0
             else if ( MEMBER_ACCESS_CONTEXT_KEY.equals( key ) )
 582  
             {
 583  0
                 result = getMemberAccess();
 584  
             }
 585  
         }
 586  
         else
 587  
         {
 588  2886
             result = values.get( key );
 589  
         }
 590  2886
         return result;
 591  
     }
 592  
 
 593  
     public Object put( String key, Object value )
 594  
     {
 595  1926
         Object result = null;
 596  
 
 597  
         // FIXME: complexity is O(n)
 598  1926
         if ( RESERVED_KEYS.contains( key ) )
 599  
         {
 600  0
             if ( CONTEXT_CONTEXT_KEY.equals( key ) )
 601  
             {
 602  0
                 throw new IllegalArgumentException( "can't change " + CONTEXT_CONTEXT_KEY + " in context" );
 603  
             }
 604  
 
 605  0
             if ( THIS_CONTEXT_KEY.equals( key ) )
 606  
             {
 607  0
                 result = getCurrentObject();
 608  0
                 setCurrentObject( value );
 609  
             }
 610  0
             else if ( ROOT_CONTEXT_KEY.equals( key ) )
 611  
             {
 612  0
                 result = getRoot();
 613  0
                 setRoot( value );
 614  
             }
 615  0
             else if ( TRACE_EVALUATIONS_CONTEXT_KEY.equals( key ) )
 616  
             {
 617  0
                 result = getTraceEvaluations() ? Boolean.TRUE : Boolean.FALSE;
 618  0
                 setTraceEvaluations( OgnlOps.booleanValue( value ) );
 619  
             }
 620  0
             else if ( LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
 621  
             {
 622  0
                 result = getLastEvaluation();
 623  0
                 lastEvaluation = (Evaluation) value;
 624  
             }
 625  0
             else if ( KEEP_LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
 626  
             {
 627  0
                 result = getKeepLastEvaluation() ? Boolean.TRUE : Boolean.FALSE;
 628  0
                 setKeepLastEvaluation( OgnlOps.booleanValue( value ) );
 629  
             }
 630  0
             else if ( CLASS_RESOLVER_CONTEXT_KEY.equals( key ) )
 631  
             {
 632  0
                 result = getClassResolver();
 633  0
                 setClassResolver( (ClassResolver) value );
 634  
             }
 635  0
             else if ( TYPE_CONVERTER_CONTEXT_KEY.equals( key ) )
 636  
             {
 637  0
                 result = getTypeConverter();
 638  0
                 setTypeConverter( (TypeConverter) value );
 639  
             }
 640  0
             else if ( MEMBER_ACCESS_CONTEXT_KEY.equals( key ) )
 641  
             {
 642  0
                 result = getMemberAccess();
 643  0
                 setMemberAccess( (MemberAccess) value );
 644  
             }
 645  
         }
 646  
         else
 647  
         {
 648  1926
             result = values.put( key, value );
 649  
         }
 650  
 
 651  1926
         return result;
 652  
     }
 653  
 
 654  
     public Object remove( Object key )
 655  
     {
 656  1728
         Object result = null;
 657  
 
 658  
         // FIXME: complexity is O(n)
 659  1728
         if ( RESERVED_KEYS.contains( key ) )
 660  
         {
 661  0
             if ( CONTEXT_CONTEXT_KEY.equals( key ) || TRACE_EVALUATIONS_CONTEXT_KEY.equals( key )
 662  
                 || KEEP_LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
 663  
             {
 664  0
                 throw new IllegalArgumentException( "can't remove " + key + " from context" );
 665  
             }
 666  
 
 667  0
             if ( THIS_CONTEXT_KEY.equals( key ) )
 668  
             {
 669  0
                 result = getCurrentObject();
 670  0
                 setCurrentObject( null );
 671  
             }
 672  0
             else if ( ROOT_CONTEXT_KEY.equals( key ) )
 673  
             {
 674  0
                 result = getRoot();
 675  0
                 setRoot( null );
 676  
             }
 677  0
             else if ( LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
 678  
             {
 679  0
                 result = lastEvaluation;
 680  0
                 setLastEvaluation( null );
 681  
             }
 682  0
             else if ( CLASS_RESOLVER_CONTEXT_KEY.equals( key ) )
 683  
             {
 684  0
                 result = getClassResolver();
 685  0
                 setClassResolver( null );
 686  
             }
 687  0
             else if ( TYPE_CONVERTER_CONTEXT_KEY.equals( key ) )
 688  
             {
 689  0
                 result = getTypeConverter();
 690  0
                 setTypeConverter( null );
 691  
             }
 692  0
             else if ( MEMBER_ACCESS_CONTEXT_KEY.equals( key ) )
 693  
             {
 694  0
                 result = getMemberAccess();
 695  0
                 setMemberAccess( null );
 696  
             }
 697  
         }
 698  
         else
 699  
         {
 700  1728
             result = values.remove( key );
 701  
         }
 702  1728
         return result;
 703  
     }
 704  
 
 705  
     public void putAll( Map<? extends String, ?> t )
 706  
     {
 707  0
         for ( Entry<? extends String, ?> entry : t.entrySet() )
 708  
         {
 709  0
             put( entry.getKey(), entry.getValue() );
 710  
         }
 711  0
     }
 712  
 
 713  
     public void clear()
 714  
     {
 715  4
         values.clear();
 716  4
         typeStack.clear();
 717  4
         accessorStack.clear();
 718  
 
 719  4
         localReferenceCounter = 0;
 720  4
         if ( localReferenceMap != null )
 721  
         {
 722  1
             localReferenceMap.clear();
 723  
         }
 724  
 
 725  4
         setRoot( null );
 726  4
         setCurrentObject( null );
 727  4
         setRootEvaluation( null );
 728  4
         setCurrentEvaluation( null );
 729  4
         setLastEvaluation( null );
 730  4
         setCurrentNode( null );
 731  4
         setClassResolver( DEFAULT_CLASS_RESOLVER );
 732  4
         setTypeConverter( DEFAULT_TYPE_CONVERTER );
 733  4
         setMemberAccess( DEFAULT_MEMBER_ACCESS );
 734  4
     }
 735  
 
 736  
     public Set<String> keySet()
 737  
     {
 738  
         /* Should root, currentObject, classResolver, typeConverter & memberAccess be included here? */
 739  0
         return values.keySet();
 740  
     }
 741  
 
 742  
     public Collection<Object> values()
 743  
     {
 744  
         /* Should root, currentObject, classResolver, typeConverter & memberAccess be included here? */
 745  0
         return values.values();
 746  
     }
 747  
 
 748  
     public Set<Entry<String, Object>> entrySet()
 749  
     {
 750  
         /* Should root, currentObject, classResolver, typeConverter & memberAccess be included here? */
 751  0
         return values.entrySet();
 752  
     }
 753  
 
 754  
     @Override
 755  
     public boolean equals( Object o )
 756  
     {
 757  0
         return values.equals( o );
 758  
     }
 759  
 
 760  
     @Override
 761  
     public int hashCode()
 762  
     {
 763  6
         return values.hashCode();
 764  
     }
 765  
 }