001 package toolbus.process;
002
003 import java.util.HashSet;
004 import java.util.Iterator;
005 import java.util.LinkedList;
006 import java.util.List;
007 import java.util.Set;
008 import java.util.Stack;
009 import toolbus.AtomList;
010 import toolbus.State;
011 import toolbus.StateElement;
012 import toolbus.TBTermFactory;
013 import toolbus.ToolBus;
014 import toolbus.atom.Atom;
015 import toolbus.environment.Environment;
016 import toolbus.exceptions.ToolBusException;
017 import toolbus.process.debug.ExecutionResult;
018 import aterm.ATerm;
019
020 /**
021 * @author paulk, Jul 23, 2002
022 */
023 public class ProcessInstance{
024 private final ProcessDefinition definition;
025 private final String processName;
026 private final int processId;
027
028 private final AtomList elements;
029
030 private final State initialState; // Needed for debugging purposes.
031 private State currentState;
032
033 private final ToolBus toolbus;
034 private final TBTermFactory tbfactory;
035
036 private final List<ATerm> subscriptions;
037 private final List<ATerm> notes;
038
039 private boolean running = true;
040
041 private boolean deregistered = false;
042
043 public ProcessInstance(ToolBus TB, ProcessCall call, int processId) throws ToolBusException{
044 toolbus = TB;
045 tbfactory = TB.getTBTermFactory();
046 this.processId = processId;
047 subscriptions = new LinkedList<ATerm>();
048 notes = new LinkedList<ATerm>();
049 call.setEvalArgs(false);
050 processName = call.getName();
051
052 definition = TB.getProcessDefinition(processName, call.actuals.getLength());
053
054 call.computeFirst();
055 call.replaceFormals(new Environment(tbfactory));
056 Stack<String> stack = new Stack<String>();
057 stack.push("TOPLEVEL");
058 call.compile(this, stack, new State());
059
060 elements = call.getAtoms();
061
062 currentState = call.getFirst();
063 initialState = call.PE.getFirst();
064 currentState.activate();
065 }
066
067 public ProcessDefinition getProcessDefinition(){
068 return definition;
069 }
070
071 public TBTermFactory getTBTermFactory(){
072 return tbfactory;
073 }
074
075 public ToolBus getToolBus(){
076 return toolbus;
077 }
078
079 public long getRunTime(){
080 return toolbus.getRunTime();
081 }
082
083 public int getProcessId(){
084 return processId;
085 }
086
087 public String getProcessName(){
088 return processName;
089 }
090
091 public void terminate(){
092 running = false;
093
094 deregisterCommunicationAtoms(elements);
095 }
096
097 public void deregisterCommunicationAtoms(AtomList atoms){
098 if(!deregistered){
099 Iterator<Atom> atomsIterator = atoms.iterator();
100 while(atomsIterator.hasNext()){
101 Atom atom = atomsIterator.next();
102 atom.destroy();
103 }
104 deregistered = true;
105 }
106 }
107
108 public boolean getNoteFromQueue(ATerm pat, Environment env){
109 Iterator<ATerm> notesIterator = notes.iterator();
110 while(notesIterator.hasNext()){
111 ATerm note = notesIterator.next();
112 if(tbfactory.matchPatternToValue(pat, env, note)){
113 notesIterator.remove();
114 //LoggerFactory.log(definition.getName(), "getNotefromQueue: " + note, IToolBusLoggerConstants.NOTES);
115 return true;
116 }
117 }
118 return false;
119 }
120
121 public boolean noNoteInQueue(ATerm pat, Environment env){
122 //LoggerFactory.log(definition.getName(), "noNoteinQueue: " + pat, IToolBusLoggerConstants.NOTES);
123 Iterator<ATerm> notesIterator = notes.iterator();
124 while(notesIterator.hasNext()){
125 ATerm note = notesIterator.next();
126 if(tbfactory.patternMatchesToValue(pat, env, note)){
127 return false;
128 }
129 }
130 return true;
131 }
132
133 public void subscribe(ATerm pat){
134 //LoggerFactory.log(definition.getName(), "subscribe " + pat, IToolBusLoggerConstants.NOTES);
135 if(!subscriptions.contains(pat)) subscriptions.add(pat);
136 }
137
138 public void unsubscribe(ATerm pat){
139 //LoggerFactory.log(definition.getName(), "unsubscribe: " + pat, IToolBusLoggerConstants.NOTES);
140 subscriptions.remove(pat);
141 }
142
143 public boolean putNoteInQueue(ATerm note){
144 //LoggerFactory.log(definition.getName(), "putNoteinQueue: " + note, IToolBusLoggerConstants.NOTES);
145
146 Iterator<ATerm> subscriptionsIterator = subscriptions.iterator();
147 while(subscriptionsIterator.hasNext()){
148 ATerm sub = subscriptionsIterator.next();
149 if(tbfactory.mightMatch(sub, note)){
150 notes.add(note);
151 return true;
152 }
153 }
154 return false;
155 }
156
157 public boolean hasNotes(){
158 return !notes.isEmpty();
159 }
160
161 public List<ATerm> getSubscriptions(){
162 return subscriptions;
163 }
164
165 public List<ATerm> getNoteQueue(){
166 return notes;
167 }
168
169 public State getProcessState(){
170 return currentState;
171 }
172
173 public boolean contains(StateElement a){
174 return currentState.contains(a);
175 }
176
177 public State getCurrentState(){
178 return currentState;
179 }
180
181 public void gotoNextStateAndActivate(){
182 currentState = currentState.gotoNextStateAndActivate();
183 }
184
185 public void gotoNextStateAndActivate(StateElement se){
186 currentState = currentState.gotoNextStateAndActivate(se);
187 }
188
189 public boolean step() throws ToolBusException{
190 if(running && currentState.execute()){
191 gotoNextStateAndActivate();
192 return true;
193 }
194 return false;
195 }
196
197 /**
198 * Executes on step in debug mode, where the state element that was executed is returned as result.
199 *
200 * @return The result of the execution (if contains the state element and partners); null if
201 * nothing was executed.
202 * @throws ToolBusException Thrown if something went wrong.
203 */
204 public ExecutionResult debugStep() throws ToolBusException{
205 if(running){
206 ExecutionResult executionResult = currentState.debugExecute();
207 if(executionResult != null){
208 StateElement stateElement = executionResult.stateElement;
209 // If we just encountered a (dynamic) process call, find out what element it executed (so we can pretent it got inlined).
210 if(stateElement instanceof ProcessCall){
211 executionResult = new ExecutionResult(((ProcessCall) stateElement).getExecutedStateElement(), executionResult.partners);
212 }else if(stateElement instanceof DynamicProcessCall){
213 executionResult = new ExecutionResult(((DynamicProcessCall) stateElement).getExecutedStateElement(), executionResult.partners);
214 }
215 gotoNextStateAndActivate();
216 return executionResult;
217 }
218 }
219 return null;
220 }
221
222 public boolean isTerminated(){
223 if(!running || currentState.size() == 0){
224 return true;
225 }
226 return false;
227 }
228
229 public String toString(){
230 return "ProcessInstance(" + definition.getName() + ", " + processId + ", " + currentState + ")";
231 }
232
233 public String showStatus(){
234 String r1 = "process " + definition.getName() + "(" + processId + "):\n " + elements.size() + " elements\n" + currentState;
235 if(subscriptions.size() > 0){
236 String r2 = "\n Subscriptions: {";
237 Iterator<ATerm> SubscriptionsIterator = subscriptions.iterator();
238 while(SubscriptionsIterator.hasNext()){
239 ATerm sub = SubscriptionsIterator.next();
240 r2 = r2 + "\n " + sub.toString();
241 }
242 if(notes.size() > 0){
243 String r3 = "}\n Note queue:{";
244 Iterator<ATerm> notesIterator = notes.iterator();
245 while(notesIterator.hasNext()){
246 ATerm note = notesIterator.next();
247
248 r3 = r3 + "\n " + note.toString();
249 }
250 r3 = r3 + "}";
251 return r1 + r2 + r3;
252 }
253 return r1 + r2;
254 }
255 return r1;
256 }
257
258 public void showAutomaton(){
259 // LoggerFactory.log("process " + processId + ": " + call, IToolBusLoggerConstants.CALLS);
260 // LoggerFactory.log("process " + processId + ": atoms: =" + elements, IToolBusLoggerConstants.CALLS);
261 // LoggerFactory.log("process " + processId + ": currentState = " + currentState, IToolBusLoggerConstants.CALLS);
262 /*Iterator<Atom> atomSetIterator = elements.iterator();
263 while(atomSetIterator.hasNext()){
264 Atom a = atomSetIterator.next();
265 //LoggerFactory.log(definition.getName(), a + " --> " + a.getFollow(), IToolBusLoggerConstants.CALLS);
266 }*/
267 }
268
269 /**
270 * Returns a complete list of state elements in this process instance.
271 * This method is only required for obtaining a reference to a state element, so we can set a
272 * break point on it when running the toolbus in debug mode.
273 *
274 * @return A complete list of atoms in this process instance.
275 */
276 public Set<StateElement> getStateElements(){
277 Set<StateElement> stateElementsSet = new HashSet<StateElement>();
278 List<StateElement> stateElementsToDo = new LinkedList<StateElement>();
279
280 stateElementsToDo.addAll(initialState.getElementsAsList());
281 do{
282 StateElement stateElement = stateElementsToDo.remove(0);
283 State state = stateElement.getFollow();
284 List<StateElement> stateElements = state.getElementsAsList();
285 Iterator<StateElement> stateElementsIterator = stateElements.iterator();
286 while(stateElementsIterator.hasNext()){
287 StateElement se = stateElementsIterator.next();
288 if(!stateElementsSet.contains(se)){
289 stateElementsToDo.add(se);
290 }
291 stateElementsSet.add(se);
292 }
293 }while(!stateElementsToDo.isEmpty());
294
295 return stateElementsSet;
296 }
297 }