]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/AbstractActionContext.java
Allow simulation stop handling in Simantics/Sequences
[simantics/platform.git] / bundles / org.simantics.simulation.sequences / src / org / simantics / simulation / sequences / action / AbstractActionContext.java
index 4fabd2243c98dedea07bb50de9dd9ac6b099270c..2adb9a045cf8a06fb525124b1a109b73f2163559 100644 (file)
@@ -14,9 +14,10 @@ public abstract class AbstractActionContext implements ActionContext {
     
     double currentTime;
     volatile boolean stopped;
-    ArrayList<Function1<Tuple0, Object>> scheduledNow = new ArrayList<Function1<Tuple0, Object>>();
-    ArrayList<Function1<Tuple0, Object>> scheduledNextStep = new ArrayList<Function1<Tuple0, Object>>();
-    PriorityQueue<Task> scheduledAt = new PriorityQueue<Task>();
+    ArrayList<Function1<Tuple0, Object>> scheduledNow = new ArrayList<>();
+    ArrayList<Function1<Tuple0, Object>> scheduledNextStep = new ArrayList<>();
+    ArrayList<Function1<StopReason, Object>> scheduledWhenStopped = new ArrayList<>();
+    PriorityQueue<Task> scheduledAt = new PriorityQueue<>();
 
        public List<Exception> exceptions; 
     
@@ -57,12 +58,22 @@ public abstract class AbstractActionContext implements ActionContext {
         else
             scheduledAt.add(new Task(time, continuation));
     }
-    
+
+    @Override
+    public void scheduleWhenStopped(Function1<StopReason, Object> continuation) {
+        scheduledWhenStopped.add(continuation);
+    }
+
     @Override
     public void stop() {
+        stop(StopReason.STOPPED);
+    }
+
+    public void stop(StopReason reason) {
         stopped = true;
+        handleStop(reason);
     }
-    
+
     public boolean isStopped() {
        synchronized (this) {
                return stopped || (scheduledNextStep.isEmpty() && scheduledAt.isEmpty());
@@ -91,7 +102,7 @@ public abstract class AbstractActionContext implements ActionContext {
                                        currentContinuation = null;
                                } catch (Exception e) {
                                        if (this.exceptions == null)
-                                               this.exceptions = new ArrayList<Exception>();
+                                               this.exceptions = new ArrayList<>();
                                        this.exceptions.add(new RuntimeException("Action failure at " + currentTime + ": " + e.getMessage(), e));
                                }
                        }
@@ -112,4 +123,27 @@ public abstract class AbstractActionContext implements ActionContext {
                }
        }
     }
+
+    private void handleStop(StopReason reason) {
+        synchronized (this) {
+            List<Function1<StopReason, Object>> stopFunctions = new ArrayList<>(scheduledWhenStopped);
+            scheduledWhenStopped.clear();
+
+            SCLContext context = SCLContext.getCurrent();
+            Object oldActionContext = context.put("sequenceAction", this);
+            try {
+                stopFunctions.forEach(f -> {
+                    try {
+                        f.apply(reason);
+                    } catch (Exception e) {
+                        if (this.exceptions == null)
+                            this.exceptions = new ArrayList<>();
+                        this.exceptions.add(new RuntimeException("Stop action failure at " + currentTime + ": " + e.getMessage(), e));
+                    }
+                });
+            } finally {
+                context.put("sequenceAction", oldActionContext);
+            }
+        }
+    }
 }