瀏覽代碼

Merge pull request #416 from Yakindu/issue_415

#415 : Added new TimingService Implementation using ExecutionScheduler
Thomas Kutz 9 年之前
父節點
當前提交
13b3998a37

+ 2 - 2
plugins/org.yakindu.sct.domain.generic/src/org/yakindu/sct/domain/generic/modules/GenericSimulationModule.java

@@ -27,12 +27,12 @@ import org.yakindu.sct.simulation.core.sexec.container.DefaultSimulationEngineFa
 import org.yakindu.sct.simulation.core.sexec.container.IExecutionContextInitializer;
 import org.yakindu.sct.simulation.core.sexec.container.ISimulationEngineFactory;
 import org.yakindu.sct.simulation.core.sexec.interpreter.DefaultExecutionFlowInterpreter;
-import org.yakindu.sct.simulation.core.sexec.interpreter.DefaultTimingService;
 import org.yakindu.sct.simulation.core.sexec.interpreter.IExecutionFlowInterpreter;
 import org.yakindu.sct.simulation.core.sexec.interpreter.IOperationMockup;
 import org.yakindu.sct.simulation.core.sexec.interpreter.IStatementInterpreter;
 import org.yakindu.sct.simulation.core.sexec.interpreter.ITimingService;
 import org.yakindu.sct.simulation.core.sexec.interpreter.JavaOperationMockup;
+import org.yakindu.sct.simulation.core.sexec.interpreter.SuspendableTimingService;
 import org.yakindu.sct.simulation.core.sexec.interpreter.StextStatementInterpreter;
 import org.yakindu.sct.simulation.core.sruntime.ExecutionContext;
 import org.yakindu.sct.simulation.core.sruntime.impl.ExecutionContextImpl;
@@ -79,7 +79,7 @@ public class GenericSimulationModule extends AbstractGenericModule {
 	}
 
 	public Class<? extends ITimingService> bindITimingService() {
-		return DefaultTimingService.class;
+		return SuspendableTimingService.class;
 	}
 
 	public Class<? extends IStatementInterpreter> bindIStatementInterpreter() {

+ 5 - 4
plugins/org.yakindu.sct.simulation.core.sexec/src/org/yakindu/sct/simulation/core/sexec/container/AbstractExecutionFlowSimulationEngine.java

@@ -69,8 +69,8 @@ public abstract class AbstractExecutionFlowSimulationEngine implements ISimulati
 	}
 
 	private void handleWrappedException(WrappedException ex) {
-		Status errorStatus = new Status(Status.ERROR, Activator.PLUGIN_ID, ERROR_DURING_SIMULATION, ex.getCause()
-				.getMessage(), ex.getCause());
+		Status errorStatus = new Status(Status.ERROR, Activator.PLUGIN_ID, ERROR_DURING_SIMULATION,
+				ex.getCause().getMessage(), ex.getCause());
 		IStatusHandler statusHandler = DebugPlugin.getDefault().getStatusHandler(errorStatus);
 		try {
 			statusHandler.handleStatus(errorStatus, getDebugTarget());
@@ -97,8 +97,8 @@ public abstract class AbstractExecutionFlowSimulationEngine implements ISimulati
 		ListBasedValidationIssueAcceptor acceptor = new ListBasedValidationIssueAcceptor();
 		ExecutionFlow flow = sequencer.transform(statechart, acceptor);
 		if (acceptor.getTraces(Severity.ERROR).size() > 0) {
-			Status errorStatus = new Status(Status.ERROR, Activator.PLUGIN_ID, ERROR_DURING_SIMULATION, acceptor
-					.getTraces(Severity.ERROR).iterator().next().toString(), null);
+			Status errorStatus = new Status(Status.ERROR, Activator.PLUGIN_ID, ERROR_DURING_SIMULATION,
+					acceptor.getTraces(Severity.ERROR).iterator().next().toString(), null);
 			IStatusHandler statusHandler = DebugPlugin.getDefault().getStatusHandler(errorStatus);
 			try {
 				statusHandler.handleStatus(errorStatus, getDebugTarget());
@@ -123,6 +123,7 @@ public abstract class AbstractExecutionFlowSimulationEngine implements ISimulati
 
 	public void suspend() {
 		suspended = true;
+		interpreter.suspend();
 	}
 
 	public void resume() {

+ 2 - 0
plugins/org.yakindu.sct.simulation.core.sexec/src/org/yakindu/sct/simulation/core/sexec/interpreter/DefaultExecutionFlowInterpreter.xtend

@@ -127,6 +127,7 @@ class DefaultExecutionFlowInterpreter implements IExecutionFlowInterpreter {
 	}
 
 	override resume() {
+		timingService.resume
 		executionContext.suspendedElements.clear
 		suspended = false
 		run
@@ -134,6 +135,7 @@ class DefaultExecutionFlowInterpreter implements IExecutionFlowInterpreter {
 
 	override suspend() {
 		suspended = true
+		timingService.pause
 	}
 
 	override exit() {

+ 3 - 1
plugins/org.yakindu.sct.simulation.core.sexec/src/org/yakindu/sct/simulation/core/sexec/interpreter/DefaultTimingService.java

@@ -20,10 +20,12 @@ import org.yakindu.sct.simulation.core.sruntime.ExecutionContext;
 
 /**
  * Implementation of {@link ITimingService} interface using standard
- * 
+ * java.util.Timer
+ * @deprecated Use the {@link SuspendableTimingService} instead
  * @author andreas muelder - Initial contribution and API
  * 
  */
+@Deprecated
 public class DefaultTimingService implements ITimingService {
 
 	public static class TimeEventTask extends TimerTask {

+ 154 - 0
plugins/org.yakindu.sct.simulation.core.sexec/src/org/yakindu/sct/simulation/core/sexec/interpreter/SuspendableTimingService.java

@@ -0,0 +1,154 @@
+/**
+ * Copyright (c) 2016 committers of YAKINDU and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     committers of YAKINDU - initial API and implementation
+ */
+package org.yakindu.sct.simulation.core.sexec.interpreter;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.yakindu.sct.simulation.core.sruntime.ExecutionContext;
+
+import com.google.inject.Singleton;
+
+/**
+ * Implementation of {@link ITimingService} interface using
+ * {@link ScheduledExecutorService}
+ * 
+ * @author andreas muelder
+ * @author thomas kutz
+ * 
+ */
+@Singleton
+public class SuspendableTimingService implements ITimingService {
+
+	protected class ScheduleEventRunnable implements Runnable {
+
+		private final ExecutionContext context;
+		private final String eventName;
+		private boolean isPeriodical;
+		private long initialDuration;
+		private long duration;
+
+		public ScheduleEventRunnable(ExecutionContext context, String eventName, boolean isPeriodical, long duration) {
+			this(context, eventName, isPeriodical, duration, duration);
+		}
+
+		public ScheduleEventRunnable(ExecutionContext context, String eventName, boolean isPeriodical,
+				long initialDuration, long duration) {
+			this.context = context;
+			this.eventName = eventName;
+			this.isPeriodical = isPeriodical;
+			this.initialDuration = initialDuration;
+			this.duration = duration;
+		}
+
+		public void run() {
+			context.getEvent(eventName).setScheduled(true);
+		}
+
+		public ExecutionContext getContext() {
+			return context;
+		}
+
+		public String getEventName() {
+			return eventName;
+		}
+
+		public boolean isPeriodical() {
+			return isPeriodical;
+		}
+
+		public long getDuration() {
+			return duration;
+		}
+
+		public long getInitialDuration() {
+			return initialDuration;
+		}
+
+		public void setInitialDuration(long initialDuration) {
+			this.initialDuration = initialDuration;
+		}
+
+	}
+
+	private ScheduledExecutorService scheduler;
+
+	private Map<String, ScheduleEventRunnable> runnables;
+	private Map<String, ScheduledFuture<?>> futures;
+
+	public SuspendableTimingService() {
+		scheduler = Executors.newScheduledThreadPool(1);
+		runnables = new HashMap<String, ScheduleEventRunnable>();
+		futures = new HashMap<String, ScheduledFuture<?>>();
+	}
+
+	public synchronized void scheduleTimeEvent(ExecutionContext context, String eventName, boolean isPeriodical,
+			long duration) {
+		if (duration <= 0)
+			duration = 1;
+		ScheduleEventRunnable eventRunnable = new ScheduleEventRunnable(context, eventName, isPeriodical, duration);
+		scheduleTimeEvent(eventRunnable);
+	}
+
+	protected void scheduleTimeEvent(ScheduleEventRunnable eventRunnable) {
+		ScheduledFuture<?> future = null;
+		if (eventRunnable.isPeriodical) {
+			future = scheduler.scheduleAtFixedRate(eventRunnable, eventRunnable.initialDuration, eventRunnable.duration,
+					TimeUnit.MILLISECONDS);
+		} else {
+			future = scheduler.schedule(eventRunnable, eventRunnable.initialDuration, TimeUnit.MILLISECONDS);
+		}
+		runnables.put(eventRunnable.getEventName(), eventRunnable);
+		futures.put(eventRunnable.getEventName(), future);
+	}
+
+	public synchronized void unscheduleTimeEvent(String eventName) {
+		ScheduledFuture<?> future = futures.remove(eventName);
+		future.cancel(false);
+		runnables.remove(eventName);
+	}
+
+	public synchronized void pause() {
+		Set<Entry<String, ScheduledFuture<?>>> entrySet = futures.entrySet();
+		for (Entry<String, ScheduledFuture<?>> entry : entrySet) {
+			ScheduledFuture<?> future = entry.getValue();
+			long delay = future.getDelay(TimeUnit.MILLISECONDS);
+			future.cancel(false);
+			ScheduleEventRunnable runnable = runnables.get(entry.getKey());
+			runnable.setInitialDuration(delay);
+		}
+		futures.clear();
+	}
+
+	public synchronized void resume() {
+		for (ScheduleEventRunnable event : runnables.values()) {
+			scheduleTimeEvent(event);
+		}
+	}
+
+	public synchronized void stop() {
+		Collection<ScheduledFuture<?>> values = futures.values();
+		for (ScheduledFuture<?> scheduledFuture : values) {
+			scheduledFuture.cancel(false);
+		}
+		futures.clear();
+		runnables.clear();
+		scheduler.shutdownNow();
+	}
+
+}