1
2
3
4
5
6
7
8
9
10
11 package org.astrogrid.jes.jobscheduler.impl.groovy;
12
13 import org.astrogrid.applications.beans.v1.cea.castor.ResultListType;
14 import org.astrogrid.applications.beans.v1.cea.castor.types.ExecutionPhase;
15 import org.astrogrid.applications.beans.v1.parameters.ParameterValue;
16 import org.astrogrid.workflow.beans.v1.Step;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20
21 import java.util.HashMap;
22 import java.util.Map;
23
24 /***(misnamed) Top level class of rules engine / state machine.
25 *
26 * Its a container for the store of states and rulebase. Provides methods to select next triggerable rule, run next rule, etc.
27 * <p>
28 * this object is serialized to xml, and then persisted to an 'extension' element in the workflow document. This 'pickles' all the execution state for
29 * the workflow, and enables the interpreter to be unpickled and continue where it left off.
30 * <p>
31 * Some of the design of this class has been constrained by needing to be picklable. In particular, a nullary constructor is required - which means that dependencies
32 * are passed in via setters.
33 * @see XStreamPickler
34 * @see ActivityStatusStore
35 * @see ActivityStatus
36 * @see Rule
37 * @see RuleStore
38 * @author Noel Winstanley nw@jb.man.ac.uk 26-Jul-2004
39 *
40 */
41 public class GroovyInterpreter {
42
43 /*** Construct a new Interpreter, with empty rule base.
44 * used by XStreamPickler to marshal / unmarshal from xml.
45 */
46 public GroovyInterpreter() {
47 this(new RuleStore());
48 }
49 /*** construct a new interpreter, passing in a list of rules
50 * Construct a new GroovyInterpreter
51 * @param rs list of {@link Rule} objects
52 */
53 public GroovyInterpreter(Map rs) {
54 this.ruleStore = new RuleStore(rs);
55
56 }
57 private static final Log logger = LogFactory.getLog(GroovyInterpreter.class);
58 /*** set of rules - keyed on their name..*/
59 protected RuleStore ruleStore;
60 /*** store of states */
61 protected ActivityStatusStore stateMap = new ActivityStatusStore();
62 /*** interface into scripting engine - used to execute script embedded within rules */
63 protected final transient JesShell shell = new JesShell();
64
65
66 /*** select a triggered rule, and then run it
67 * @see #findNext
68 * @throws ScriptEngineException
69 */
70 public void runNext() throws ScriptEngineException{
71 try {
72 Rule rule = ruleStore.findNext(shell,stateMap);
73 rule.fire(shell,stateMap,ruleStore);
74 } catch (Exception e) {
75 throw new ScriptEngineException("Failed to run next",e);
76 }
77 }
78 /*** run the interpreter, until no more rules can be triggered
79 * @see #runNext */
80 public void run() throws ScriptEngineException {
81 try {
82 for (Rule rule= ruleStore.findNext(shell,stateMap); rule != null; rule = ruleStore.findNext(shell,stateMap)) {
83 rule.fire(shell,stateMap,ruleStore);
84 }
85
86 }catch (Exception e) {
87 throw new ScriptEngineException("Failed to run interpreter",e);
88 }
89 }
90
91 /*** update the status of an step - called when a cea server returns information about execution progress of a step execytion */
92 public void updateStepStatus(Step step, ExecutionPhase phase) {
93 if (phase.equals(ExecutionPhase.COMPLETED)) {
94 stateMap.setStatus(step.getId(),Status.FINISH);
95 } else if (phase.equals(ExecutionPhase.ERROR)) {
96 stateMap.setStatus(step.getId(),Status.ERROR);
97 } else {
98 return;
99 }
100
101 }
102 /***store the results of a step execution - called when a cea server returns step execution results.
103 * @param step
104 * @param results
105 */
106 public void storeResults(Step step, ResultListType results) {
107 String id = step.getId();
108
109 Map resultsMap = new HashMap();
110 for (int i = 0; i < results.getResultCount(); i++) {
111 ParameterValue pval = results.getResult(i);
112 resultsMap.put(pval.getName(),pval.getValue());
113 }
114
115 stateMap.getEnv(step.getId()).set(step.getResultVar(),resultsMap);
116 stateMap.setStatus(step.getId() + "-results",Status.FINISHED);
117 }
118
119 /*** sets link to the jes interface component - provides the rules engine with necessary hooks into jes server.
120 * this is a setter, rather than my usual constructor-dependency-injection, so that the GroovyInterpreter can be created via reflection.
121 * @param jesInterface The jesInterface to set.
122 */
123 public void setJesInterface(JesInterface jesInterface) {
124 this.shell.setJesInterface(jesInterface);
125 }
126 /***
127 * Returns <code>true</code> if this <code>GroovyInterpreter</code> is the same as the o argument.
128 *
129 * @return <code>true</code> if this <code>GroovyInterpreter</code> is the same as the o argument.
130 */
131 public boolean equals(Object o) {
132 if (this == o) {
133 return true;
134 }
135 if (o == null) {
136 return false;
137 }
138 if (o.getClass() != getClass()) {
139 return false;
140 }
141 GroovyInterpreter castedObj = (GroovyInterpreter) o;
142 return ((this.ruleStore == null
143 ? castedObj.ruleStore == null
144 : this.ruleStore.equals(castedObj.ruleStore))
145 && (this.stateMap == null
146 ? castedObj.stateMap == null
147 : this.stateMap.equals(castedObj.stateMap)) );
148 }
149 /***
150 * Override hashCode.
151 *
152 * @return the Objects hashcode.
153 */
154 public int hashCode() {
155 int hashCode = 1;
156 hashCode = 31 * hashCode + (logger == null ? 0 : logger.hashCode());
157 hashCode = 31
158 * hashCode
159 + (ruleStore == null ? 0 : ruleStore.hashCode());
160 hashCode = 31 * hashCode + (stateMap == null ? 0 : stateMap.hashCode());
161 return hashCode;
162 }
163 public String toString() {
164 StringBuffer buffer = new StringBuffer();
165 buffer.append("[GroovyInterpreter:");
166 buffer.append(" ruleStore: ");
167 buffer.append(ruleStore);
168 buffer.append(" stateMap: ");
169 buffer.append(stateMap);
170
171 buffer.append("]");
172 return buffer.toString();
173 }
174
175
176 }
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227