Reference Manual for Gracelets - 2.0.0.SP2SourceForge.net Logo
5.4 - Framework : Variable Contexts
Gracelets is designed to be easily integrated into different frameworks. Many frameworks (like JBoss Seam) extend the concept of the basic JSF scopes (request, session, application) and thus have different implementations. Gracelets scripts need to be able to easily access variables and set variables in these scopes. Thus the variable context API was designed as an abstract bridge to different scope based frameworks. However, Gracelets itself comes with a primitive default variable context implementation that defines a view, request, conversation, session and application scopes. When another framework is being used, its variable context implementation will take precedence over the default implementation, thus allowing it to have the first shot at resolving variables.

For example, the JBoss Seam extension uses this api to allow gracelet scripts to have access to JBoss Seam components and scope variables.

The package containing the classes for this api is in the gracelets.api.context package. And the main interfaces for creating a variable context are the gracelets.api.context.VariableContext interface and the gracelets.api.context.Scope interface. These interfaces are defined as follows:

VariableContext.java
Toggle Line Numbers
1 package gracelets.api.context; 
2  
3 import gracelets.api.context.factory.Factory; 
4 import gracelets.api.context.factory.FactoryStore; 
5 import groovy.lang.GroovyObject; 
6  
7 import java.io.Serializable; 
8 import java.util.List; 
9 import java.util.Map; 
10  
11 import javax.faces.event.PhaseEvent; 
12  
13 /** 
14  * This is the abstraction of a variable context, which represents a set of logical {@link Scope}'s that 
15  * normally compose an environment of sorts. 
16  *  
17  * @author elponderador 
18  * @author $Author: ponderator $ 
19  * @version $Id: VariableContext.java 1949 2009-11-13 22:38:05Z ponderator $ 
20  */ 
21 public interface VariableContext extends Serializable, GroovyObject, FactoryStore { 
22  
23     /** 
24      * This will loop through the scopes in this context in a logical sequence until it 
25      * finds a scope that contains an entry corresponding to the key. 
26      *  
27      * @param caller The object that is calling this context 
28      * @param key The key that references an entry that may exist in one of the scopes in this context 
29      * @return The value that corresponds to the entry found in reference to the key, otherwise null 
30      */ 
31     Object get (Object caller, Object key); 
32      
33     /** 
34      * This allows one to limit the lookup to a particular scope. 
35      *  
36      * @param caller The object that is calling this context 
37      * @param key The key that references an entry that may exist in the scope specified 
38      * @param scope The scope to search for the reference 
39      * @return The value that corresponds to the entry found in the scope, otherwise null 
40      *  
41      * @see #get(Object, Object) 
42      */ 
43     Object get (Object caller, Object key, Scope scope); 
44      
45     /** 
46      * This should first search the scopes in this context to see if one already 
47      * contains an entry with the same name as the key provided, if so it should replace 
48      * the value in the scope found, otherwise it should store the key/value entry 
49      * in a scope that is determined to be the default, normally the same scope returned 
50      * by {@link #getDefaultScope()}. 
51      *  
52      * @param caller The object that is calling this context 
53      * @param key The key that will be associated with the provided value 
54      * @param value The value that will be associated with the key 
55      * @return A reference to this object for chaining purposes 
56      */ 
57     VariableContext set (Object caller, Object key, Object value); 
58      
59     /** 
60      * @param caller The object that is calling this context 
61      * @param key The key that will be associated with the provided value 
62      * @param scope The scope in which the key/value should be stored 
63      * @param value The value that will be associated with the key 
64      * @return A reference to this object for chaining purposes 
65      */ 
66     VariableContext set (Object caller, Object key, Scope scope, Object value); 
67      
68     /** 
69      * @param scope The scope that should be checked 
70      * @return True if this context has a scope by this name, otherwise false 
71      */ 
72     boolean handlesScope (Scope scope); 
73      
74     /** 
75      * @param name The string name representation of a particular scope 
76      * @return The scope that corresponds to the name, or null if no such scope exists in this context 
77      */ 
78     Scope getScopeByName (String name); 
79      
80     /** 
81      * @return A collection of the scopes that this context contains, in logical order. 
82      */ 
83     List<Scope> getAvailableScopes (); 
84      
85     /** 
86      * @return The default scope for this context, or null if there is no default scope. 
87      */ 
88     Scope getDefaultScope (); 
89      
90     /** 
91      * @param name The name of the entry that may exist in a particular scope 
92      * @return The scope that contained an entry with the name passed, or the {@link #getDefaultScope()} if it is active, otherwise null 
93      */ 
94     Scope getDefaultScope (Object name); 
95      
96     /** 
97      * @param name The scope needed 
98      * @return A context that will only resolve to one single scope, or null if no such scope exists 
99      */ 
100     ScopedContext getScopedContext (String name); 
101      
102     /** 
103      * Allowing variable contexts to participate in the JSF lifecycle 
104      *  
105      * @param evt The current phase event 
106      */ 
107     void beforePhase (PhaseEvent evt); 
108      
109     /** 
110      * Allowing variable contexts to participate in the JSF lifecycle 
111      *  
112      * @param evt The current phase event 
113      */ 
114     void afterPhase (PhaseEvent evt); 
115      
116     /** 
117      * @param key The name of an entry or factory 
118      * @return True if there is a value associated with a key in one of the scopes, or if there is a factory with the same name as the key 
119      */ 
120     boolean isSetOrHasFactory (Object key); 
121      
122     /** 
123      * @param name The name of the factory being requested 
124      * @param scope The scope to force, or null if any scope 
125      * @return The value generated by the factory or null if no such factory exists 
126      */ 
127     Object getFactoryValue (Object name, Scope scope); 
128      
129     /** 
130      * All variable contexts must support conversation context. 
131      *  
132      * @return The conversation manager for this context. 
133      */ 
134     ConversationManager getConversationManager(); 
135      
136     /** 
137      * This should be called for cleanup purposes before being discarded 
138      */ 
139     void cleanup (); 
140      
141 } 
Scope.java
Toggle Line Numbers
1 package gracelets.api.context; 
2  
3 import gracelets.api.Gracelets; 
4 import gracelets.api.context.factory.Factory; 
5  
6 import java.io.Serializable; 
7  
8 /** 
9  * This is the abstraction of a variable scope allowing {@link Gracelets} to interface 
10  * with different systems via the scope concept. A scope refers to a particular set of 
11  * variables that can have a particular life span and can be contextual. 
12  *  
13  * @author elponderador 
14  * @author $Author: ponderator $ 
15  * @version $Id: Scope.java 1933 2009-10-27 18:01:11Z ponderator $ 
16  *  
17  * @param K The type of keys allowed by this scope 
18  * @param V The type of values allowed by this scope 
19  */ 
20 public interface Scope<K,V> extends Serializable { 
21      
22     /** 
23      * @return A string name representation of this scope 
24      */ 
25     String getName (); 
26      
27     /** 
28      * @param key The key which should be checked for existence in the scope 
29      * @return True if there is an entry by the name specified by the key in this scope, otherwise false 
30      */ 
31     boolean containsKey (K key); 
32      
33     /** 
34      * Associates the value with the key and stores it in this scope. 
35      *  
36      * @param key The name which should be associated with the value in this scope 
37      * @param value The value which should be associated with the key in this scope 
38      * @return A reference to this scope for chaining purposes 
39      */ 
40     Scope set (K key, V value); 
41      
42     /** 
43      * Removes the entry referenced by the key from this scope. 
44      *  
45      * @param key The name of the entry that should be removed 
46      * @return A reference to this scope for chaining purposes 
47      */ 
48     Scope remove (K key); 
49      
50     /** 
51      * @param key The key of the entry whose value should be retrieved  
52      * @return The value corresponding to the entry referenced by the key 
53      */ 
54     V get (K key); 
55      
56     /** 
57      * This does not correspond to the lifecycle of the scope, but rather the request level 
58      * instances that allow access to the scope. 
59      *  
60      * This should be called before the scope instance is discarded, for cleanup purposes. 
61      */ 
62     void cleanup (); 
63      
64     /** 
65      * @return True if this scope is active, that is if it is currently accessible, otherwise false 
66      */ 
67     boolean isActive (); 
68      
69     /** 
70      * @return True if this scope represents a scope that is in relation to the {@link ConversationManager}, otherwise false 
71      */ 
72     boolean isConversational (); 
73      
74 } 
Above the variable context will define inside of itself various scopes. The scope interface was designed so that one can use different scope implementations easily and rearragne their order in different variable contexts. For instance is you want to make your own variable context, but don't feel up to writing a conversation level scope, you can reuse the one defined in the default implementation of Gracelets. The variable context and generally its scopes are instantiated for every request. At the end of the request, the cleanup() method is called so that it can remove or close any resources it needs to.

One major feature that was added in Gracelets 2.0.0 was an independent factory solution. This solution is tightly connected to the Variable Contexts. In each scope implementation, you can handle how factories are added/removed. Factories are implementations of the gracelets.api.context.factory.Factory interface which is defined as follows:

Factory.java
Toggle Line Numbers
1 package gracelets.api.context.factory; 
2  
3 import gracelets.api.Gracelets; 
4 import gracelets.api.context.Scope; 
5 import gracelets.api.jsf.expression.GraceletExpressionSource; 
6 import gracelets.api.resource.GraceletSource; 
7  
8 /** 
9  * This is the basic interface/contract for all factories in the {@link Gracelets} abstracted factory system.   
10  *  
11  * @author elponderador 
12  * 
13  */ 
14 public interface Factory<T> { 
15  
16     /** 
17      * @return The string representation name of the scope this factory will generate values for 
18      */ 
19     String getScope (); 
20      
21     /** 
22      * @return The value to be stored in the scope when this factory is required to generate a value 
23      */ 
24     T generate (); 
25      
26     /** 
27      * @return The expression source this factory belongs to, or null if it is not related to an expression source 
28      */ 
29     GraceletExpressionSource getSource (); 
30      
31 } 
Since Factories are application level definitions (independent of the scope they outject to), they need a place on the application level to hold their state. Gracelets stores these in an implementation dependent Variable Context Manager to store and retreive factories. There are a few basic implementations of the Factory interface, mainly to handle Closures as factories and Java based classes to also be able to generate factory objects.

The basic idea of a factory is that when a context variable in a particular scope does not currently have a value, the factory is used to generate the value automatically.

In conclusion, if you want to integrate a framework that has its own scopes for certain variables, you can use this extensible variable context api and provide the instance via a gracelet extension.