Reference Manual for Gracelets - 2.0.0.RC2SourceForge.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 1704 2009-07-10 00:32:35Z 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      * Allowing variable contexts to participate in the JSF lifecycle 
98      *  
99      * @param evt The current phase event 
100      */ 
101     void beforePhase (PhaseEvent evt); 
102      
103     /** 
104      * Allowing variable contexts to participate in the JSF lifecycle 
105      *  
106      * @param evt The current phase event 
107      */ 
108     void afterPhase (PhaseEvent evt); 
109      
110     /** 
111      * @param key The name of an entry or factory 
112      * @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 
113      */ 
114     boolean isSetOrHasFactory (Object key); 
115      
116     /** 
117      * All variable contexts must support conversation context. 
118      *  
119      * @return The conversation manager for this context. 
120      */ 
121     ConversationManager getConversationManager(); 
122      
123     /** 
124      * This should be called for cleanup purposes before being discarded 
125      */ 
126     void cleanup (); 
127      
128 } 
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 1704 2009-07-10 00:32:35Z 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 should be called before the scope is discarded, for cleanup purposes. 
58      */ 
59     void cleanup (); 
60      
61     /** 
62      * @return True if this scope is active, that is if it is currently accessible, otherwise false 
63      */ 
64     boolean isActive (); 
65      
66     /** 
67      * @return True if this scope represents a scope that is in relation to the {@link ConversationManager}, otherwise false 
68      */ 
69     boolean isConversational (); 
70      
71 } 
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.