001    /**
002     * @author paulk, Jul 22, 2002
003     */
004    
005    package toolbus.process;
006    
007    import java.util.ArrayList;
008    import java.util.List;
009    import java.util.Stack;
010    
011    import toolbus.AtomList;
012    import toolbus.State;
013    import toolbus.StateElement;
014    import toolbus.TBTermFactory;
015    import toolbus.TBTermVar;
016    import toolbus.atom.Tau;
017    import toolbus.environment.Environment;
018    import toolbus.exceptions.NoSuchProcessDefinitionException;
019    import toolbus.exceptions.ToolBusException;
020    import toolbus.exceptions.ToolBusExecutionException;
021    import toolbus.parsercup.PositionInformation;
022    import toolbus.process.debug.ExecutionResult;
023    import aterm.ATerm;
024    import aterm.ATermAppl;
025    import aterm.ATermList;
026    
027    public class DynamicProcessCall extends ProcessExpression implements StateElement{
028            private String name;
029            
030            private TBTermVar nameAsVar;
031            
032            protected final ATermList originalActuals;
033            protected ATermList actuals;
034            
035            private ATermList formals;
036            
037            private Environment env;
038            
039            private ProcessDefinition definition = null; // May remain null for dynamic calls to non-existing processes
040            
041            protected ProcessExpression PE;
042            
043            protected ProcessInstance processInstance;
044            
045            private final State firstState;
046            
047            private boolean executing = false;
048            
049            private boolean activated = false;
050            
051            private Stack<String> calls;
052            
053            private ATerm test;
054            private Environment testEnv;
055            
056            public DynamicProcessCall(String name, ATermList actuals, TBTermFactory tbfactory, PositionInformation posInfo){
057                    super(tbfactory, posInfo);
058                    this.name = name;
059                    this.originalActuals = actuals;
060                    this.actuals = actuals;
061                    
062                    firstState = new State();
063                    firstState.addElement(this);
064            }
065            
066            protected ProcessExpression copy(){
067                    return new DynamicProcessCall(name, actuals, tbfactory, getPosInfo());
068            }
069            
070            protected void computeFirst(){
071                    // System.err.println("ProcessCall.computeFirst: " + firstState);
072                    setFirst(firstState);
073            }
074            
075            protected void replaceFormals(Environment e) throws ToolBusException{
076                    //System.err.println("ProcessCall.replaceFormals(" + name + "): " + env);
077                    env = e.copy();
078                    
079                    // env = e;
080                    actuals = (ATermList) tbfactory.replaceFormals(originalActuals, env);
081            }
082            
083            protected void compile(ProcessInstance P, Stack<String> calls, State follows) throws ToolBusException{
084                    processInstance = P;
085                    this.calls = calls;
086                    setFollow(follows);
087                    nameAsVar = tbfactory.mkVar(tbfactory.make(name), calls.peek(), tbfactory.StrType);
088                    
089                    definition = null;
090            }
091            
092            private void compileStaticOrDynamicCall() throws ToolBusException{
093                    if(calls.contains(name)){
094                            throw new ToolBusExecutionException("Recursive call of "+name, getPosInfo());
095                    }
096                    
097                    definition = processInstance.getToolBus().getProcessDefinition(name, originalActuals.getLength());
098                    
099                    // System.err.println("name = " + name);
100                    // System.err.println("definition = " + definition);
101                    
102                    actuals = (ATermList) tbfactory.replaceFormals(originalActuals, env);
103                    PE = definition.getProcessExpression(actuals);
104                    
105                    // System.err.println("ProcessCall.compile(" + name + ", " + processInstance + "," + PE + ")");
106                    formals = definition.getFormals();
107                    
108                    env.introduceBindings(formals, actuals, true);
109                    actuals = (ATermList) tbfactory.replaceFormals(actuals, env);
110                    
111                    // System.err.println("ProcessCall.compile(" + name + "): " + env);
112                    // System.err.println("actuals = " + actuals);
113                    PE.computeFirst();
114                    PE.replaceFormals(env);
115                    
116                    calls.push(name);
117                    PE.compile(processInstance, calls, firstState);
118                    calls.pop();
119                    
120                    PE.getFirst().setTest(test, testEnv);
121                    // env.removeBindings(formals);
122                    // System.err.println(name + " expanded as:\n" + PE);
123            }
124            
125            private void initDynamicCall() throws ToolBusException{
126                    ATermAppl dynprocessname = (ATermAppl) env.getValue(nameAsVar);
127                    name = dynprocessname.getName();
128                    compileStaticOrDynamicCall();
129                    //System.err.println("Dynamic process name " + name + " => " + dynprocessname);
130            }
131            
132            private void finishCall(){
133                    activated = executing = false;
134                    definition = null;
135                    AtomList callElements = PE.getAtoms();
136                    PE = null;
137                    processInstance.deregisterCommunicationAtoms(callElements);
138            }
139            
140            public AtomList getAtoms(){
141                    AtomList r;
142                    if(PE != null){
143                            r = PE.getAtoms();
144                    }else{
145                            r = new AtomList();
146                    }
147                    // System.err.println(name + ".getAtoms => " + r);
148                    return r;
149            }
150            
151            public String getName(){
152                    return name;
153            }
154            
155            public String toString(){
156                    return "DynamicProcessCall(" + name + ", " + originalActuals + ")";
157            }
158            
159            
160            // Implementation of the StateElement interface
161            
162            public boolean contains(StateElement a){
163                    // if(!isStaticCall){ System.err.println(name + ": contains " + a); }
164                    
165                    return ((definition != null) && activated) ? PE.getFirst().contains(a) : false;
166            }
167            
168            public ProcessInstance getProcess(){
169                    return processInstance;
170            }
171            
172            public void setTest(ATerm test, Environment env) throws ToolBusException{
173                    this.test = test;
174                    this.testEnv = env;
175            }
176            
177            public List<ATerm> getTests(){
178                    List<ATerm> testExpressions = new ArrayList<ATerm>(1);
179                    if(test != null) testExpressions.add(test);
180                    return testExpressions;
181            }
182            
183            public boolean isEnabled(){
184                    return (activated && definition != null);
185            }
186            
187            public State gotoNextStateAndActivate(){
188                    if(!(activated || executing)){
189                            State follow = getFollow();
190                            follow.activate();
191                            return follow;
192                    }
193                    executing = true;
194                    return PE.getFirst().gotoNextStateAndActivate();
195            }
196            
197            public State gotoNextStateAndActivate(StateElement se){
198                    if(!(activated || executing)){
199                            State follow = getFollow();
200                            follow.activate();
201                            return follow;
202                    }
203                    executing = true;
204                    return PE.getFirst().gotoNextStateAndActivate(se);
205            }
206            
207            public void activate(){
208                    if(activated && executing) return;
209                    
210                    try{
211                            initDynamicCall();
212                    }catch(NoSuchProcessDefinitionException nspdex){
213                            // Ignore this and emulate Delta.
214                            activated = false;
215                            return;                 
216                    }catch(ToolBusException e){
217    //                      e.printStackTrace();
218                            activated = false;
219                            return;
220                    }
221                    
222                    activated = true;
223                    PE.getFirst().activate();
224            }
225            
226            public boolean execute() throws ToolBusException{
227                    if(isEnabled()){
228                            if(!executing){
229                                    if(PE.getFirst().size() == 0){
230                                            // System.err.println("case size = 0");
231                                            executing = true;
232                                            return true;
233                                    }
234                                    executing = PE.getFirst().execute();
235                                    return executing;
236                            }
237                            finishCall();
238                            return true;
239                    }
240                    return false;
241            }
242            
243            public ProcessInstance[] debugExecute() throws ToolBusException{
244                    if(isEnabled()){
245                            if(!executing){
246                                    if(PE.getFirst().size() == 0){
247                                            executing = true;
248                                            return new ProcessInstance[0];
249                                    }
250                                    ExecutionResult er = PE.getFirst().debugExecute();
251                                    if(er != null){
252                                            executing = true;
253                                            return er.partners;
254                                    }
255                                    executing = false;
256                                    return null;
257                            }
258                            finishCall();
259                            return new ProcessInstance[0];
260                    }
261                    return null;
262            }
263            
264            /**
265             * Returns the last, by this process call, executed state element.
266             * (This method is used for debugging only).
267             * @return The last, by this process call, executed state element; may be null if this process call isn't currently executing.
268             */
269            public StateElement getExecutedStateElement(){
270                    if(!executing) return new Tau(tbfactory, null); // Pretend nothing happened if the call was just completed.
271                    
272                    StateElement executedStateElement = PE.getFirst().getLastExecutedStateElement();
273                    while(executedStateElement instanceof ProcessCall){
274                            executedStateElement = ((ProcessCall) executedStateElement).getExecutedStateElement();
275                    }
276                    return executedStateElement;
277            }
278    }