001: package org.jbpm.context.exe;
002:
003: import java.io.Serializable;
004: import java.util.ArrayList;
005: import java.util.Collection;
006: import java.util.HashMap;
007: import java.util.Iterator;
008: import java.util.Map;
009:
010: import org.apache.commons.logging.Log;
011: import org.apache.commons.logging.LogFactory;
012: import org.jbpm.JbpmException;
013: import org.jbpm.context.log.VariableDeleteLog;
014: import org.jbpm.graph.exe.ProcessInstance;
015: import org.jbpm.graph.exe.Token;
016:
017: public abstract class VariableContainer implements Serializable {
018:
019: protected Map variableInstances = null;
020:
021: protected abstract VariableContainer getParentVariableContainer();
022:
023: public abstract Token getToken();
024:
025: // variables ////////////////////////////////////////////////////////////////
026:
027: public Object getVariable(String name) {
028: Object value = null;
029: if (hasVariableLocally(name)) {
030: value = getVariableLocally(name);
031: } else {
032: VariableContainer parent = getParentVariableContainer();
033: if (parent != null) {
034: // check upwards in the token hierarchy
035: value = parent.getVariable(name);
036: }
037: }
038: return value;
039: }
040:
041: public void setVariable(String name, Object value) {
042: VariableContainer parent = getParentVariableContainer();
043: if (hasVariableLocally(name) || parent == null) {
044: setVariableLocally(name, value);
045:
046: } else {
047: // so let's action to the parent token's TokenVariableMap
048: parent.setVariable(name, value);
049: }
050: }
051:
052: public boolean hasVariable(String name) {
053: boolean hasVariable = false;
054:
055: // if the variable is present in the variable instances
056: if (hasVariableLocally(name)) {
057: hasVariable = true;
058:
059: } else {
060: VariableContainer parent = getParentVariableContainer();
061: if (parent != null) {
062: hasVariable = parent.hasVariable(name);
063: }
064: }
065:
066: return hasVariable;
067: }
068:
069: public void deleteVariable(String name) {
070: if (name == null) {
071: throw new JbpmException("name is null");
072: }
073: if (hasVariableLocally(name)) {
074: deleteVariableLocally(name);
075: }
076: }
077:
078: /**
079: * adds all the given variables to this variable container.
080: * The method {@link #setVariables(Map)} is the same as this method, but
081: * it was added for naming consitency.
082: */
083: public void addVariables(Map variables) {
084: setVariables(variables);
085: }
086:
087: /**
088: * adds all the given variables to this variable container. It doesn't
089: * remove any existing variables unless they are overwritten by the given
090: * variables.
091: * This method is the same as {@link #addVariables(Map)} and this method
092: * was added for naming consistency.
093: */
094: public void setVariables(Map variables) {
095: if (variables != null) {
096: Iterator iter = variables.entrySet().iterator();
097: while (iter.hasNext()) {
098: Map.Entry entry = (Map.Entry) iter.next();
099: setVariable((String) entry.getKey(), entry.getValue());
100: }
101: }
102: }
103:
104: public Map getVariables() {
105: Map variables = getVariablesLocally();
106: VariableContainer parent = getParentVariableContainer();
107: if (parent != null) {
108: Map parentVariables = parent.getVariablesLocally();
109: parentVariables.putAll(variables);
110: variables = parentVariables;
111: }
112: return variables;
113: }
114:
115: public Map getVariablesLocally() {
116: Map variables = new HashMap();
117: if (variableInstances != null) {
118: Iterator iter = variableInstances.entrySet().iterator();
119: while (iter.hasNext()) {
120: Map.Entry entry = (Map.Entry) iter.next();
121: String name = (String) entry.getKey();
122: VariableInstance variableInstance = (VariableInstance) entry
123: .getValue();
124: if (!variables.containsKey(name)) {
125: variables.put(name, variableInstance.getValue());
126: }
127: }
128: }
129: return variables;
130: }
131:
132: // local variable methods ///////////////////////////////////////////////////
133:
134: public boolean hasVariableLocally(String name) {
135: return ((variableInstances != null) && (variableInstances
136: .containsKey(name)));
137: }
138:
139: public Object getVariableLocally(String name) {
140: Object value = null;
141:
142: // if the variable is present in the variable instances
143: if (hasVariableLocally(name)) {
144: value = getVariableInstance(name).getValue();
145: }
146:
147: return value;
148: }
149:
150: public void deleteVariableLocally(String name) {
151: deleteVariableInstance(name);
152: }
153:
154: public void setVariableLocally(String name, Object value) {
155: if (name == null) {
156: throw new JbpmException("name is null");
157: }
158:
159: VariableInstance variableInstance = getVariableInstance(name);
160: // if there is already a variable instance and it doesn't support the current type...
161: if ((variableInstance != null)
162: && (!variableInstance.supports(value))) {
163: // delete the old variable instance
164: log.debug("variable type change. deleting '" + name
165: + "' from '" + this + "'");
166: deleteVariableInstance(name);
167: variableInstance = null;
168: }
169:
170: if (variableInstance == null) {
171: log.debug("create variable '" + name + "' in '" + this
172: + "' with value '" + value + "'");
173: variableInstance = VariableInstance.create(getToken(),
174: name, value);
175: addVariableInstance(variableInstance);
176: } else {
177: log.debug("update variable '" + name + "' in '" + this
178: + "' to value '" + value + "'");
179: variableInstance.setValue(value);
180: }
181: }
182:
183: // local variable instances /////////////////////////////////////////////////
184:
185: public VariableInstance getVariableInstance(String name) {
186: return (variableInstances != null ? (VariableInstance) variableInstances
187: .get(name)
188: : null);
189: }
190:
191: public Map getVariableInstances() {
192: return variableInstances;
193: }
194:
195: public void addVariableInstance(VariableInstance variableInstance) {
196: if (variableInstances == null) {
197: variableInstances = new HashMap();
198: }
199: variableInstances.put(variableInstance.getName(),
200: variableInstance);
201: // only additions are registered in the updated variable containers
202: // because it is only used in the save operation to check wether there
203: // are unpersistable variables added
204: addUpdatedVariableContainer();
205: }
206:
207: public void deleteVariableInstance(String name) {
208: if (variableInstances != null) {
209: VariableInstance variableInstance = (VariableInstance) variableInstances
210: .remove(name);
211: if (variableInstance != null) {
212: getToken().addLog(
213: new VariableDeleteLog(variableInstance));
214: variableInstance.removeReferences();
215: }
216: }
217: }
218:
219: void addUpdatedVariableContainer() {
220: ContextInstance contextInstance = getContextInstance();
221: if (contextInstance != null) {
222: if (contextInstance.updatedVariableContainers == null) {
223: contextInstance.updatedVariableContainers = new ArrayList();
224: }
225: contextInstance.updatedVariableContainers.add(this );
226: }
227: }
228:
229: public ContextInstance getContextInstance() {
230: Token token = getToken();
231: ProcessInstance processInstance = (token != null ? token
232: .getProcessInstance() : null);
233: return (processInstance != null ? processInstance
234: .getContextInstance() : null);
235: }
236:
237: public static Collection getUpdatedVariableContainers(
238: ProcessInstance processInstance) {
239: return processInstance.getContextInstance().updatedVariableContainers;
240: }
241:
242: private static Log log = LogFactory.getLog(VariableContainer.class);
243: }
|