View Javadoc

1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */ 
16  package org.apache.commons.betwixt.expression;
17  
18  import java.util.HashMap;
19  import java.util.Map;
20  
21  import org.apache.commons.betwixt.BindingConfiguration;
22  import org.apache.commons.betwixt.strategy.ObjectStringConverter;
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  
26  /*** <p><code>Context</code> describes the context used to evaluate
27    * bean expressions.
28    * This is mostly a bean together with a number of context variables.
29    * Context variables are named objects.
30    * In other words, 
31    * a context variable associates an object with a string.</p>
32    *
33    * <p> Logging during expression evaluation is done through the logging
34    * instance held by this class. 
35    * The object initiating the evaluation should control this logging 
36    * and so passing a <code>Log</code> instance is enforced by the constructors.</p>
37    *
38    * <p><code>Context</code> is a natural place to include shared evaluation code.
39    * One of the problems that you get with object graphs is that they can be cyclic.
40    * Xml cannot (directly) include cycles. 
41    * Therefore <code>betwixt</code> needs to find and deal properly with cycles.
42    * The algorithm used is to check the parentage of a new child.
43    * If the child is a parent then that operation fails. </p>
44    *
45    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
46    */
47  public class Context {
48  
49      /*** Evaluate this bean */
50      private Object bean;
51      /*** Variables map */
52      private Map variables;
53      /*** 
54       * Logging uses commons-logging <code>Log</code> 
55       * named <code>org.apache.commons.betwixt</code> 
56       */
57      private Log log; 
58      /*** Configuration for dynamic binding properties */
59      private BindingConfiguration bindingConfiguration;
60      
61      /*** 
62       * Construct context with default log 
63       */
64      public Context() {
65          this( null, LogFactory.getLog( Context.class ) );
66      }
67      
68      /*** Convenience constructor sets evaluted bean and log.
69        *
70        * @param bean evaluate expressions against this bean
71        * @param log log to this logger
72        * @deprecated 0.5 use constructor which takes a BindingConfiguration
73        */
74      public Context(Object bean, Log log) {
75          this( bean, log, new BindingConfiguration() );
76      }
77  
78      
79      /*** Convenience constructor sets evaluted bean and log.
80        *
81        * @param bean evaluate expressions against this bean
82        * @param log log to this logger
83        * @param bindingConfiguration not null
84        */
85      public Context(Object bean, Log log, BindingConfiguration bindingConfiguration) {
86          this( bean, new HashMap(), log,  bindingConfiguration );
87      }
88      
89      /***
90        * Construct a cloned context.
91        * The constructed context should share bean, variables, log and binding configuration.
92        * @param context duplicate the attributes of this bean
93        */
94      public Context( Context context ) {
95          this(context.bean, context.variables, context.log, context.bindingConfiguration);
96      }
97      
98      
99      /*** Convenience constructor sets evaluted bean, context variables and log.
100       *
101       * @param bean evaluate expressions against this bean 
102       * @param variables context variables
103       * @param log log to this logger
104       * @deprecated 0.5 use constructor which takes a converter
105       */
106     public Context(Object bean, Map variables, Log log) {
107         this( bean, variables, log, new BindingConfiguration() );
108     }
109     
110     /*** Convenience constructor sets evaluted bean, context variables and log.
111       *
112       * @param bean evaluate expressions against this bean 
113       * @param variables context variables
114       * @param log log to this logger
115       * @param bindingConfiguration not null
116       */
117     public Context(Object bean, Map variables, Log log, BindingConfiguration bindingConfiguration) {
118         this.bean = bean;
119         this.variables = variables;
120         this.log = log;
121         this.bindingConfiguration = bindingConfiguration;
122     }
123 
124     /*** Returns a new child context with the given bean but the same log and variables. 
125      * 
126      * @param newBean create a child context for this bean
127      * @return new Context with new bean but shared variables 
128      */
129     // TODO: need to think about whether this is a good idea and how subclasses
130     // should handle this
131     public Context newContext(Object newBean) {
132         Context context = new Context(this);
133         context.setBean( newBean );
134         return context;
135     }
136     
137     /*** 
138      * Gets the current bean.
139      * @return the bean against which expressions are evaluated
140      */
141     public Object getBean() {
142         return bean;
143     }
144 
145     /*** 
146      * Set the current bean.
147      * @param bean the Object against which expressions will be evaluated
148      */
149     public void setBean(Object bean) {
150         this.bean = bean;
151     }    
152     
153     /*** 
154       * Gets context variables.
155       * @return map containing variable values keyed by variable name
156       */
157     public Map getVariables() {
158         return variables;
159     }
160 
161     /*** 
162      * Sets context variables. 
163      * @param variables map containing variable values indexed by varibable name Strings
164      */
165     public void setVariables(Map variables) {
166         this.variables = variables;
167     }    
168 
169     /*** 
170      * Gets the value of a particular context variable.
171      * @param name the name of the variable whose value is to be returned
172      * @return the variable value or null if the variable isn't set
173      */
174     public Object getVariable(String name) {
175         return variables.get( name );
176     }
177 
178     /*** 
179      * Sets the value of a particular context variable.
180      * @param name the name of the variable
181      * @param value the value of the variable
182      */    
183     public void setVariable(String name, Object value) {
184         variables.put( name, value );
185     }
186     
187     /*** 
188      * Gets the current log.  
189      *
190      * @return the implementation to which this class logs
191      */
192     public Log getLog() {
193         return log;
194     }
195 
196     /*** 
197      * Set the log implementation to which this class logs
198      * 
199      * @param log the implemetation that this class should log to
200      */
201     public void setLog(Log log) {
202         this.log = log;
203     }
204     
205     /*** 
206      * Gets object &lt;-&gt; string converter.
207      * @return the Converter to be used for conversions, not null
208      * @since 0.5 
209      */
210     public ObjectStringConverter getObjectStringConverter() {
211         return bindingConfiguration.getObjectStringConverter();
212     }
213     
214     /*** 
215      * Should <code>ID</code>'s and <code>IDREF</code> attributes 
216      * be used to cross-reference matching objects? 
217      *
218      * @return true if <code>ID</code> and <code>IDREF</code> 
219      * attributes should be used to cross-reference instances
220      * @since 0.5
221      */
222     public boolean getMapIDs() {
223         return bindingConfiguration.getMapIDs();
224     }
225     
226     /***
227      * The name of the attribute which can be specified in the XML to override the
228      * type of a bean used at a certain point in the schema.
229      *
230      * <p>The default value is 'className'.</p>
231      * 
232      * @return The name of the attribute used to overload the class name of a bean
233      * @since 0.5
234      */
235     public String getClassNameAttribute() {
236         return bindingConfiguration.getClassNameAttribute();
237     }
238 
239     /***
240      * Sets the name of the attribute which can be specified in 
241      * the XML to override the type of a bean used at a certain 
242      * point in the schema.
243      *
244      * <p>The default value is 'className'.</p>
245      * 
246      * @param classNameAttribute The name of the attribute used to overload the class name of a bean
247      * @since 0.5
248      */
249     public void setClassNameAttribute(String classNameAttribute) {
250         bindingConfiguration.setClassNameAttribute( classNameAttribute );
251     }
252 }