1 package org.apache.commons.ognl;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
34
35
36
37
38 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 private static boolean defaultTraceEvaluations = false;
63
64 private static boolean defaultKeepLastEvaluation = false;
65
66 public static final DefaultClassResolver DEFAULT_CLASS_RESOLVER = new DefaultClassResolver();
67
68 public static final TypeConverter DEFAULT_TYPE_CONVERTER = new DefaultTypeConverter();
69
70 public static final MemberAccess DEFAULT_MEMBER_ACCESS = new DefaultMemberAccess( false );
71
72 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 private boolean traceEvaluations = defaultTraceEvaluations;
81
82 private Evaluation rootEvaluation;
83
84 private Evaluation currentEvaluation;
85
86 private Evaluation lastEvaluation;
87
88 private boolean keepLastEvaluation = defaultKeepLastEvaluation;
89
90 private Map<String, Object> values = new HashMap<String, Object>( 23 );
91
92 private ClassResolver classResolver = DEFAULT_CLASS_RESOLVER;
93
94 private TypeConverter typeConverter = DEFAULT_TYPE_CONVERTER;
95
96 private MemberAccess memberAccess = DEFAULT_MEMBER_ACCESS;
97
98 static
99 {
100 String s;
101
102 RESERVED_KEYS.add( CONTEXT_CONTEXT_KEY );
103 RESERVED_KEYS.add( ROOT_CONTEXT_KEY );
104 RESERVED_KEYS.add( THIS_CONTEXT_KEY );
105 RESERVED_KEYS.add( TRACE_EVALUATIONS_CONTEXT_KEY );
106 RESERVED_KEYS.add( LAST_EVALUATION_CONTEXT_KEY );
107 RESERVED_KEYS.add( KEEP_LAST_EVALUATION_CONTEXT_KEY );
108 RESERVED_KEYS.add( CLASS_RESOLVER_CONTEXT_KEY );
109 RESERVED_KEYS.add( TYPE_CONVERTER_CONTEXT_KEY );
110 RESERVED_KEYS.add( MEMBER_ACCESS_CONTEXT_KEY );
111
112 try
113 {
114 s = System.getProperty( PROPERTY_KEY_PREFIX + ".traceEvaluations" );
115 if ( s != null )
116 {
117 defaultTraceEvaluations = Boolean.valueOf( s.trim() );
118 }
119 s = System.getProperty( PROPERTY_KEY_PREFIX + ".keepLastEvaluation" );
120 if ( s != null )
121 {
122 defaultKeepLastEvaluation = Boolean.valueOf( s.trim() );
123 }
124 }
125 catch ( SecurityException ex )
126 {
127
128 }
129 }
130
131 private Stack<Class<?>> typeStack = new Stack<Class<?>>();
132
133 private Stack<Class<?>> accessorStack = new Stack<Class<?>>();
134
135 private int localReferenceCounter = 0;
136
137 private Map<String, LocalReference> localReferenceMap = null;
138
139
140
141
142 public OgnlContext()
143 {
144 }
145
146
147
148
149
150 public OgnlContext( ClassResolver classResolver, TypeConverter typeConverter, MemberAccess memberAccess )
151 {
152 this();
153 if ( classResolver != null )
154 {
155 this.classResolver = classResolver;
156 }
157 if ( typeConverter != null )
158 {
159 this.typeConverter = typeConverter;
160 }
161 if ( memberAccess != null )
162 {
163 this.memberAccess = memberAccess;
164 }
165 }
166
167 public OgnlContext( Map<String, Object> values )
168 {
169 super();
170 this.values = values;
171 }
172
173 public OgnlContext( ClassResolver classResolver, TypeConverter typeConverter, MemberAccess memberAccess,
174 Map<String, Object> values )
175 {
176 this( classResolver, typeConverter, memberAccess );
177 this.values = values;
178 }
179
180 public void setValues( Map<String, Object> value )
181 {
182 values.putAll( value );
183 }
184
185 public Map<String, Object> getValues()
186 {
187 return values;
188 }
189
190 public void setClassResolver( ClassResolver value )
191 {
192 if ( value == null )
193 {
194 throw new IllegalArgumentException( "cannot set ClassResolver to null" );
195 }
196 classResolver = value;
197 }
198
199 public ClassResolver getClassResolver()
200 {
201 return classResolver;
202 }
203
204 public void setTypeConverter( TypeConverter value )
205 {
206 if ( value == null )
207 {
208 throw new IllegalArgumentException( "cannot set TypeConverter to null" );
209 }
210 typeConverter = value;
211 }
212
213 public TypeConverter getTypeConverter()
214 {
215 return typeConverter;
216 }
217
218 public void setMemberAccess( MemberAccess value )
219 {
220 if ( value == null )
221 {
222 throw new IllegalArgumentException( "cannot set MemberAccess to null" );
223 }
224 memberAccess = value;
225 }
226
227 public MemberAccess getMemberAccess()
228 {
229 return memberAccess;
230 }
231
232 public void setRoot( Object value )
233 {
234 root = value;
235 accessorStack.clear();
236 typeStack.clear();
237 currentObject = value;
238
239 if ( currentObject != null )
240 {
241 setCurrentType( currentObject.getClass() );
242 }
243 }
244
245 public Object getRoot()
246 {
247 return root;
248 }
249
250 public boolean getTraceEvaluations()
251 {
252 return traceEvaluations;
253 }
254
255 public void setTraceEvaluations( boolean value )
256 {
257 traceEvaluations = value;
258 }
259
260 public Evaluation getLastEvaluation()
261 {
262 return lastEvaluation;
263 }
264
265 public void setLastEvaluation( Evaluation value )
266 {
267 lastEvaluation = value;
268 }
269
270
271
272
273
274
275 public void recycleLastEvaluation()
276 {
277 OgnlRuntime.getEvaluationPool().recycleAll( lastEvaluation );
278 lastEvaluation = null;
279 }
280
281
282
283
284
285 public boolean getKeepLastEvaluation()
286 {
287 return keepLastEvaluation;
288 }
289
290
291
292
293
294 public void setKeepLastEvaluation( boolean value )
295 {
296 keepLastEvaluation = value;
297 }
298
299 public void setCurrentObject( Object value )
300 {
301 currentObject = value;
302 }
303
304 public Object getCurrentObject()
305 {
306 return currentObject;
307 }
308
309 public void setCurrentAccessor( Class<?> type )
310 {
311 accessorStack.add( type );
312 }
313
314 public Class<?> getCurrentAccessor()
315 {
316 if ( accessorStack.isEmpty() )
317 {
318 return null;
319 }
320
321 return accessorStack.peek();
322 }
323
324 public Class<?> getPreviousAccessor()
325 {
326 if ( accessorStack.isEmpty() )
327 {
328 return null;
329 }
330
331 if ( accessorStack.size() > 1 )
332 {
333 return accessorStack.get( accessorStack.size() - 2 );
334 }
335
336 return null;
337 }
338
339 public Class<?> getFirstAccessor()
340 {
341 if ( accessorStack.isEmpty() )
342 {
343 return null;
344 }
345
346 return accessorStack.get( 0 );
347 }
348
349
350
351
352
353
354 public Class<?> getCurrentType()
355 {
356 if ( typeStack.isEmpty() )
357 {
358 return null;
359 }
360
361 return typeStack.peek();
362 }
363
364 public void setCurrentType( Class<?> type )
365 {
366 typeStack.add( type );
367 }
368
369
370
371
372
373
374
375 public Class<?> getPreviousType()
376 {
377 if ( typeStack.isEmpty() )
378 {
379 return null;
380 }
381
382 if ( typeStack.size() > 1 )
383 {
384 return typeStack.get( typeStack.size() - 2 );
385 }
386
387 return null;
388 }
389
390 public void setPreviousType( Class<?> type )
391 {
392 if ( typeStack.isEmpty() || typeStack.size() < 2 )
393 {
394 return;
395 }
396
397 typeStack.set( typeStack.size() - 2, type );
398 }
399
400 public Class<?> getFirstType()
401 {
402 if ( typeStack.isEmpty() )
403 {
404 return null;
405 }
406
407 return typeStack.get( 0 );
408 }
409
410 public void setCurrentNode( Node value )
411 {
412 currentNode = value;
413 }
414
415 public Node getCurrentNode()
416 {
417 return currentNode;
418 }
419
420
421
422
423 public Evaluation getCurrentEvaluation()
424 {
425 return currentEvaluation;
426 }
427
428 public void setCurrentEvaluation( Evaluation value )
429 {
430 currentEvaluation = value;
431 }
432
433
434
435
436
437 public Evaluation getRootEvaluation()
438 {
439 return rootEvaluation;
440 }
441
442 public void setRootEvaluation( Evaluation value )
443 {
444 rootEvaluation = value;
445 }
446
447
448
449
450
451 public Evaluation getEvaluation( int relativeIndex )
452 {
453 Evaluation result = null;
454
455 if ( relativeIndex <= 0 )
456 {
457 result = currentEvaluation;
458 while ( ( ++relativeIndex < 0 ) && ( result != null ) )
459 {
460 result = result.getParent();
461 }
462 }
463 return result;
464 }
465
466
467
468
469
470 public void pushEvaluation( Evaluation value )
471 {
472 if ( currentEvaluation != null )
473 {
474 currentEvaluation.addChild( value );
475 }
476 else
477 {
478 setRootEvaluation( value );
479 }
480 setCurrentEvaluation( value );
481 }
482
483
484
485
486 public Evaluation popEvaluation()
487 {
488 Evaluation result;
489
490 result = currentEvaluation;
491 setCurrentEvaluation( result.getParent() );
492 if ( currentEvaluation == null )
493 {
494 setLastEvaluation( getKeepLastEvaluation() ? result : null );
495 setRootEvaluation( null );
496 setCurrentNode( null );
497 }
498 return result;
499 }
500
501 public int incrementLocalReferenceCounter()
502 {
503 return ++localReferenceCounter;
504 }
505
506 public void addLocalReference( String key, LocalReference reference )
507 {
508 if ( localReferenceMap == null )
509 {
510 localReferenceMap = new LinkedHashMap<String, LocalReference>();
511 }
512
513 localReferenceMap.put( key, reference );
514 }
515
516 public Map<String, LocalReference> getLocalReferences()
517 {
518 return localReferenceMap;
519 }
520
521
522 public int size()
523 {
524 return values.size();
525 }
526
527 public boolean isEmpty()
528 {
529 return values.isEmpty();
530 }
531
532 public boolean containsKey( Object key )
533 {
534 return values.containsKey( key );
535 }
536
537 public boolean containsValue( Object value )
538 {
539 return values.containsValue( value );
540 }
541
542 public Object get( Object key )
543 {
544 Object result = null;
545
546
547 if ( RESERVED_KEYS.contains( key ) )
548 {
549 if ( THIS_CONTEXT_KEY.equals( key ) )
550 {
551 result = getCurrentObject();
552 }
553 else if ( ROOT_CONTEXT_KEY.equals( key ) )
554 {
555 result = getRoot();
556 }
557 else if ( CONTEXT_CONTEXT_KEY.equals( key ) )
558 {
559 result = this;
560 }
561 else if ( TRACE_EVALUATIONS_CONTEXT_KEY.equals( key ) )
562 {
563 result = getTraceEvaluations() ? Boolean.TRUE : Boolean.FALSE;
564 }
565 else if ( LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
566 {
567 result = getLastEvaluation();
568 }
569 else if ( KEEP_LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
570 {
571 result = getKeepLastEvaluation() ? Boolean.TRUE : Boolean.FALSE;
572 }
573 else if ( CLASS_RESOLVER_CONTEXT_KEY.equals( key ) )
574 {
575 result = getClassResolver();
576 }
577 else if ( TYPE_CONVERTER_CONTEXT_KEY.equals( key ) )
578 {
579 result = getTypeConverter();
580 }
581 else if ( MEMBER_ACCESS_CONTEXT_KEY.equals( key ) )
582 {
583 result = getMemberAccess();
584 }
585 }
586 else
587 {
588 result = values.get( key );
589 }
590 return result;
591 }
592
593 public Object put( String key, Object value )
594 {
595 Object result = null;
596
597
598 if ( RESERVED_KEYS.contains( key ) )
599 {
600 if ( CONTEXT_CONTEXT_KEY.equals( key ) )
601 {
602 throw new IllegalArgumentException( "can't change " + CONTEXT_CONTEXT_KEY + " in context" );
603 }
604
605 if ( THIS_CONTEXT_KEY.equals( key ) )
606 {
607 result = getCurrentObject();
608 setCurrentObject( value );
609 }
610 else if ( ROOT_CONTEXT_KEY.equals( key ) )
611 {
612 result = getRoot();
613 setRoot( value );
614 }
615 else if ( TRACE_EVALUATIONS_CONTEXT_KEY.equals( key ) )
616 {
617 result = getTraceEvaluations() ? Boolean.TRUE : Boolean.FALSE;
618 setTraceEvaluations( OgnlOps.booleanValue( value ) );
619 }
620 else if ( LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
621 {
622 result = getLastEvaluation();
623 lastEvaluation = (Evaluation) value;
624 }
625 else if ( KEEP_LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
626 {
627 result = getKeepLastEvaluation() ? Boolean.TRUE : Boolean.FALSE;
628 setKeepLastEvaluation( OgnlOps.booleanValue( value ) );
629 }
630 else if ( CLASS_RESOLVER_CONTEXT_KEY.equals( key ) )
631 {
632 result = getClassResolver();
633 setClassResolver( (ClassResolver) value );
634 }
635 else if ( TYPE_CONVERTER_CONTEXT_KEY.equals( key ) )
636 {
637 result = getTypeConverter();
638 setTypeConverter( (TypeConverter) value );
639 }
640 else if ( MEMBER_ACCESS_CONTEXT_KEY.equals( key ) )
641 {
642 result = getMemberAccess();
643 setMemberAccess( (MemberAccess) value );
644 }
645 }
646 else
647 {
648 result = values.put( key, value );
649 }
650
651 return result;
652 }
653
654 public Object remove( Object key )
655 {
656 Object result = null;
657
658
659 if ( RESERVED_KEYS.contains( key ) )
660 {
661 if ( CONTEXT_CONTEXT_KEY.equals( key ) || TRACE_EVALUATIONS_CONTEXT_KEY.equals( key )
662 || KEEP_LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
663 {
664 throw new IllegalArgumentException( "can't remove " + key + " from context" );
665 }
666
667 if ( THIS_CONTEXT_KEY.equals( key ) )
668 {
669 result = getCurrentObject();
670 setCurrentObject( null );
671 }
672 else if ( ROOT_CONTEXT_KEY.equals( key ) )
673 {
674 result = getRoot();
675 setRoot( null );
676 }
677 else if ( LAST_EVALUATION_CONTEXT_KEY.equals( key ) )
678 {
679 result = lastEvaluation;
680 setLastEvaluation( null );
681 }
682 else if ( CLASS_RESOLVER_CONTEXT_KEY.equals( key ) )
683 {
684 result = getClassResolver();
685 setClassResolver( null );
686 }
687 else if ( TYPE_CONVERTER_CONTEXT_KEY.equals( key ) )
688 {
689 result = getTypeConverter();
690 setTypeConverter( null );
691 }
692 else if ( MEMBER_ACCESS_CONTEXT_KEY.equals( key ) )
693 {
694 result = getMemberAccess();
695 setMemberAccess( null );
696 }
697 }
698 else
699 {
700 result = values.remove( key );
701 }
702 return result;
703 }
704
705 public void putAll( Map<? extends String, ?> t )
706 {
707 for ( Entry<? extends String, ?> entry : t.entrySet() )
708 {
709 put( entry.getKey(), entry.getValue() );
710 }
711 }
712
713 public void clear()
714 {
715 values.clear();
716 typeStack.clear();
717 accessorStack.clear();
718
719 localReferenceCounter = 0;
720 if ( localReferenceMap != null )
721 {
722 localReferenceMap.clear();
723 }
724
725 setRoot( null );
726 setCurrentObject( null );
727 setRootEvaluation( null );
728 setCurrentEvaluation( null );
729 setLastEvaluation( null );
730 setCurrentNode( null );
731 setClassResolver( DEFAULT_CLASS_RESOLVER );
732 setTypeConverter( DEFAULT_TYPE_CONVERTER );
733 setMemberAccess( DEFAULT_MEMBER_ACCESS );
734 }
735
736 public Set<String> keySet()
737 {
738
739 return values.keySet();
740 }
741
742 public Collection<Object> values()
743 {
744
745 return values.values();
746 }
747
748 public Set<Entry<String, Object>> entrySet()
749 {
750
751 return values.entrySet();
752 }
753
754 @Override
755 public boolean equals( Object o )
756 {
757 return values.equals( o );
758 }
759
760 @Override
761 public int hashCode()
762 {
763 return values.hashCode();
764 }
765 }