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    }