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