Browse Source

Refactoring of thread save wrapper and runnable wrapper.

Markus Mühlbrandt 9 years ago
parent
commit
444e57460c

+ 2 - 2
plugins/org.yakindu.sct.generator.java/library/FeatureTypeLibrary.xmi

@@ -33,7 +33,7 @@
         optional="true"
         optional="true"
         parameterType="BOOLEAN"/>
         parameterType="BOOLEAN"/>
   </types>
   </types>
-  <types name="EventBasedRunnableWrapper"
+  <types name="RunnableWrapper"
       comment="Generates a runnable wrapper for the state machine"
       comment="Generates a runnable wrapper for the state machine"
       optional="true">
       optional="true">
     <parameters
     <parameters
@@ -45,7 +45,7 @@
         comment="Name suffix"
         comment="Name suffix"
         optional="true"/>
         optional="true"/>
   </types>
   </types>
-  <types name="CycleBasedSynchronizedWrapper"
+  <types name="SynchronizedWrapper"
       optional="true">
       optional="true">
     <parameters
     <parameters
         name="namePrefix"
         name="namePrefix"

+ 136 - 94
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/CycleBasedSynchronizedWrapper.xtend

@@ -1,12 +1,12 @@
 /**
 /**
-  Copyright (c) 2015 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:
-  	Markus Mühlbrandt - Initial contribution and API
-*/
+ *   Copyright (c) 2015 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:
+ *   	Markus Mühlbrandt - Initial contribution and API
+ */
 
 
 package org.yakindu.sct.generator.java
 package org.yakindu.sct.generator.java
 
 
@@ -21,8 +21,10 @@ import org.yakindu.sct.model.sexec.ExecutionFlow
 import org.yakindu.sct.model.sgen.GeneratorEntry
 import org.yakindu.sct.model.sgen.GeneratorEntry
 import org.yakindu.sct.model.stext.stext.InterfaceScope
 import org.yakindu.sct.model.stext.stext.InterfaceScope
 
 
+import static org.eclipse.xtext.util.Strings.*
+
 /**
 /**
- * Generates the runnable wrapper for the state machine. This wrapper implies event based execution semantics. 
+ * Generates the cycle bases synchronized wrapper for the state machine.
  */
  */
 class CycleBasedSynchronizedWrapper {
 class CycleBasedSynchronizedWrapper {
 
 
@@ -33,68 +35,84 @@ class CycleBasedSynchronizedWrapper {
 	@Inject protected extension Navigation
 	@Inject protected extension Navigation
 	@Inject protected extension ITypeSystem
 	@Inject protected extension ITypeSystem
 	@Inject protected extension ICodegenTypeSystemAccess
 	@Inject protected extension ICodegenTypeSystemAccess
-	
+
 	def generateCycleWrapper(ExecutionFlow flow, GeneratorEntry entry, IFileSystemAccess fsa) {
 	def generateCycleWrapper(ExecutionFlow flow, GeneratorEntry entry, IFileSystemAccess fsa) {
-		
+
 		var filename = flow.getImplementationPackagePath(entry) + '/' + flow.cycleWrapperClassName(entry).java
 		var filename = flow.getImplementationPackagePath(entry) + '/' + flow.cycleWrapperClassName(entry).java
 		var content = content(flow, entry)
 		var content = content(flow, entry)
 		fsa.generateFile(filename, content)
 		fsa.generateFile(filename, content)
 	}
 	}
-	
-	
+
 	def protected content(ExecutionFlow flow, GeneratorEntry entry) '''
 	def protected content(ExecutionFlow flow, GeneratorEntry entry) '''
 		«entry.licenseText»
 		«entry.licenseText»
 		package «flow.getImplementationPackageName(entry)»;
 		package «flow.getImplementationPackageName(entry)»;
 		«flow.createImports(entry)»
 		«flow.createImports(entry)»
 		
 		
 		/**
 		/**
-		 * Subclass of «flow.statemachineClassName». This wrapper provides a thread-safe instance of the state machine.
+		 * Runnable wrapper of «flow.statemachineClassName». This wrapper provides a thread-safe
+		 * instance of the state machine.
 		 * 
 		 * 
-		 * Please report bugs and issues... 
+		 * Please report bugs and issues...
 		 */
 		 */
 		
 		
-		public class «flow.cycleWrapperClassName(entry)» extends «flow.statemachineClassName» {
+		public class «flow.cycleWrapperClassName(entry)» implements «flow.statemachineInterfaceName» {
 			
 			
 			«flow.createFieldDeclarations(entry)»
 			«flow.createFieldDeclarations(entry)»
+			
+			public «flow.cycleWrapperClassName(entry)»() {
+				«FOR scope : flow.interfaceScopes»
+					«scope.interfaceName.asEscapedIdentifier» = new «scope.wrapperInterfaceName(entry)»();
+				«ENDFOR»
+			}
+			
 			«flow.interfaceAccessors»
 			«flow.interfaceAccessors»
 			«flow.timingFunctions(entry)»
 			«flow.timingFunctions(entry)»
 			
 			
 			/**
 			/**
 			 * init() will be delegated thread-safely to the wrapped state machine. 
 			 * init() will be delegated thread-safely to the wrapped state machine. 
 			 */ 
 			 */ 
-			public synchronized void init() {
-				statemachine.init();
+			public void init() {
+				synchronized(statemachine) {
+					statemachine.init();
+				}
 			}
 			}
 			
 			
 			/**
 			/**
 			 * enter() will be delegated thread-safely to the wrapped state machine.  
 			 * enter() will be delegated thread-safely to the wrapped state machine.  
 			 */ 
 			 */ 
-			public synchronized void enter() {
-				statemachine.enter();
+			public void enter() {
+				synchronized(statemachine) {
+					statemachine.enter();
+				}
 			}
 			}
 			
 			
 			/**
 			/**
 			 * exit() will be delegated thread-safely to the wrapped state machine.  
 			 * exit() will be delegated thread-safely to the wrapped state machine.  
 			 */ 
 			 */ 
-			public synchronized void exit() {
-				statemachine.exit();
+			public void exit() {
+				synchronized(statemachine) {
+					statemachine.exit();
+				}
 			}
 			}
 			
 			
 			/**
 			/**
 			 * isActive() will be delegated thread-safely to the wrapped state machine.  
 			 * isActive() will be delegated thread-safely to the wrapped state machine.  
 			 */ 
 			 */ 
-			public synchronized boolean isActive() {
-				return statemachine.isActive();
+			public boolean isActive() {
+				synchronized(statemachine) {
+					return statemachine.isActive();
+				}
 			}
 			}
 			
 			
 			/**
 			/**
 			 * isFinal() will be delegated thread-safely to the wrapped state machine.  
 			 * isFinal() will be delegated thread-safely to the wrapped state machine.  
 			 */ 
 			 */ 
-			public synchronized boolean isFinal() {
-				return statemachine.isFinal();
+			public boolean isFinal() {
+				synchronized(statemachine) {
+					return statemachine.isFinal();
+				}
 			}
 			}
 			
 			
-			
 			/**
 			/**
 			 * runCycle() will be delegated thread-safely to the wrapped state machine.  
 			 * runCycle() will be delegated thread-safely to the wrapped state machine.  
 			 */ 
 			 */ 
@@ -104,93 +122,74 @@ class CycleBasedSynchronizedWrapper {
 					statemachine.runCycle();
 					statemachine.runCycle();
 				}
 				}
 			}
 			}
-
-			/**
-			 * This method will start the main execution loop for the state machine. 
-			 * First it will init and enter the state machine implicitly and then will start processing events 
-			 * from the event queue until the thread is interrupted. 
-			 */
-			@Override
-			public void run() {
-			
-				boolean terminate = false;
-				
-				while(!(terminate || Thread.currentThread().isInterrupted())) {
-			
-					try {
-						
-						Runnable eventProcessor = eventQueue.take();
-						eventProcessor.run();
-						
-					} catch (InterruptedException e) {
-						terminate = true;
-					}
-				}			
-			}
-
-			
 		}
 		}
 	'''
 	'''
-	
-	def protected createImports(ExecutionFlow flow, GeneratorEntry entry) '''
-		import java.util.concurrent.BlockingQueue;
-		import java.util.concurrent.LinkedBlockingQueue;
 
 
+	def protected createImports(ExecutionFlow flow, GeneratorEntry entry) '''
 		«IF entry.createInterfaceObserver && flow.hasOutgoingEvents»
 		«IF entry.createInterfaceObserver && flow.hasOutgoingEvents»
-		import java.util.LinkedList;
-		import java.util.List;
+			import java.util.List;
 		«ENDIF»
 		«ENDIF»
 		«IF flow.timed»
 		«IF flow.timed»
 			import «entry.getBasePackageName()».ITimer;
 			import «entry.getBasePackageName()».ITimer;
 			import «entry.getBasePackageName()».ITimerCallback;
 			import «entry.getBasePackageName()».ITimerCallback;
 		«ENDIF»
 		«ENDIF»
 	'''
 	'''
-	
+
 	def protected createFieldDeclarations(ExecutionFlow flow, GeneratorEntry entry) '''
 	def protected createFieldDeclarations(ExecutionFlow flow, GeneratorEntry entry) '''
-		
-		
 		/**
 		/**
-		 *
-		 * Lock to provide thread save access.
-		 *
+		 * The core state machine is simply wrapped and the event processing will be
+		 * delegated to that state machine instance. This instance will be created
+		 * implicitly.
 		 */
 		 */
-		protected ReentrantLock lock = new ReentrantLock(true);
-		
-		«FOR scope : flow.interfaceScopes»
-		/**
-		 * Interface object for «scope.interfaceName»
-		 */		
-		protected «scope.interfaceName» «scope.interfaceName.asEscapedIdentifier» = new «scope.interfaceName»() {
-			«scope.toImplementation(entry)»
-		};
+		protected «flow.statemachineClassName» statemachine = new «flow.statemachineClassName»();
 		
 		
+		«FOR scope : flow.interfaceScopes SEPARATOR newLine»
+			/**
+			 * Interface object for «scope.interfaceName»
+			 */		
+			protected class «scope.wrapperInterfaceName(entry)» implements «scope.interfaceName» {
+				«scope.toImplementation(entry)»
+			};
+			
+			protected «scope.interfaceName» «scope.interfaceName.asEscapedIdentifier»;
 		«ENDFOR»
 		«ENDFOR»
-		
 	'''
 	'''
-	
-	def protected toImplementation(InterfaceScope scope, GeneratorEntry entry) '''				
+
+	def protected toImplementation(InterfaceScope scope, GeneratorEntry entry) '''
+		
+		«IF entry.createInterfaceObserver && scope.hasOutgoingEvents»
+			«scope.generateListeners»
+		«ENDIF»
+		«IF scope.hasOperations»
+			«scope.generateOperationCallback»
+		«ENDIF»
 		«FOR event : scope.eventDefinitions»
 		«FOR event : scope.eventDefinitions»
 			«IF event.direction == Direction::IN»
 			«IF event.direction == Direction::IN»
 				«IF event.type != null && !isSame(event.type, getType(GenericTypeSystem.VOID))»
 				«IF event.type != null && !isSame(event.type, getType(GenericTypeSystem.VOID))»
 					public void raise«event.name.asName»(final «event.type.targetLanguageName» value) {
 					public void raise«event.name.asName»(final «event.type.targetLanguageName» value) {
-						lock.lock();
-						statemachine.get«scope.interfaceName»().raise«event.name.asName»(value);
-						lock.unlock();
+						
+						synchronized (statemachine) {
+							statemachine.get«scope.interfaceName»().raise«event.name.asName»(value);
+							statemachine.runCycle();
+						}
 					}
 					}
 					
 					
 				«ELSE»
 				«ELSE»
 					public void raise«event.name.asName»() {
 					public void raise«event.name.asName»() {
-						lock.lock();
-						statemachine.get«scope.interfaceName»().raise«event.name.asName»();
-						lock.unlock();
+						
+						synchronized (statemachine) {
+							statemachine.get«scope.interfaceName»().raise«event.name.asName»();
+							statemachine.runCycle();
+						}
 					}
 					}
 					
 					
 				«ENDIF»
 				«ENDIF»
 			«ENDIF»
 			«ENDIF»
 			«IF event.direction == Direction::OUT»
 			«IF event.direction == Direction::OUT»
 				public boolean isRaised«event.name.asName»() {
 				public boolean isRaised«event.name.asName»() {
-						lo
+					synchronized(statemachine) {
 						return statemachine.get«scope.interfaceName»().isRaised«event.name.asName»();
 						return statemachine.get«scope.interfaceName»().isRaised«event.name.asName»();
+					}
 				}
 				}
 				
 				
 				«IF event.type != null && !isSame(event.type, getType(GenericTypeSystem.VOID))»
 				«IF event.type != null && !isSame(event.type, getType(GenericTypeSystem.VOID))»
@@ -219,7 +218,25 @@ class CycleBasedSynchronizedWrapper {
 			«ENDIF»
 			«ENDIF»
 		«ENDFOR»
 		«ENDFOR»
 	'''
 	'''
-
+	
+	protected def generateListeners(InterfaceScope scope) '''
+		public List<«scope.getInterfaceListenerName»> getListeners() {
+			synchronized(statemachine) {
+				return statemachine.get«scope.interfaceName»().getListeners();
+			}
+		}
+		
+	'''
+	
+	protected def generateOperationCallback(InterfaceScope scope) '''
+		public void set«scope.getInterfaceOperationCallbackName»(«scope.getInterfaceOperationCallbackName» operationCallback) {
+			synchronized(statemachine) {
+				statemachine.get«scope.interfaceName»().set«scope.getInterfaceOperationCallbackName»(operationCallback);
+			}
+		}
+		
+	'''
+	
 	def protected interfaceAccessors(ExecutionFlow flow) '''
 	def protected interfaceAccessors(ExecutionFlow flow) '''
 		«FOR scope : flow.interfaceScopes»
 		«FOR scope : flow.interfaceScopes»
 			public synchronized «scope.interfaceName» get«scope.interfaceName»() {
 			public synchronized «scope.interfaceName» get«scope.interfaceName»() {
@@ -228,18 +245,40 @@ class CycleBasedSynchronizedWrapper {
 		«ENDFOR»
 		«ENDFOR»
 	'''
 	'''
 
 
-
 	def protected timingFunctions(ExecutionFlow flow, GeneratorEntry entry) '''
 	def protected timingFunctions(ExecutionFlow flow, GeneratorEntry entry) '''
 		«IF flow.timed»
 		«IF flow.timed»
+			/*================ TIME EVENT HANDLING ================
+			
+			/** An external timer instance is required. */
+			protected ITimer externalTimer;
+			
+			/** Internally we use a timer proxy that queues time events together with other input events. */
+			protected ITimer timerProxy = new ITimer() {
+				/** Simply delegate to external timer with a modified callback. */
+				@Override
+				public void setTimer(ITimerCallback callback, int eventID, long time,
+						boolean isPeriodic) {
+					externalTimer.setTimer(«flow.cycleWrapperClassName(entry)».this, eventID, time, isPeriodic);
+				}
+				
+				@Override
+				public void unsetTimer(ITimerCallback callback, int eventID) {
+					externalTimer.unsetTimer(«flow.cycleWrapperClassName(entry)».this, eventID);
+				}
+			};
+			
 			/**
 			/**
-			 * Set the {@link ITimer} for the state machine. It must be set
-			 * externally on a timed state machine before a run cycle can be correct
-			 * executed.
+			 * Set the {@link ITimer} for the state machine. It must be set externally
+			 * on a timed state machine before a run cycle can be correct executed.
 			 * 
 			 * 
 			 * @param timer
 			 * @param timer
 			 */
 			 */
-			public synchronized void setTimer(ITimer timer) {
-				super.setTimer(timerProxy);
+			public void setTimer(ITimer timer) {
+				synchronized(statemachine) {
+					this.externalTimer = timer;
+					/* the wrapped state machine uses timer proxy as timer */
+					statemachine.setTimer(timerProxy);
+				}
 			}
 			}
 			
 			
 			/**
 			/**
@@ -247,14 +286,17 @@ class CycleBasedSynchronizedWrapper {
 			* 
 			* 
 			* @return {@link ITimer}
 			* @return {@link ITimer}
 			*/
 			*/
-			public synchronized ITimer getTimer() {
+			public ITimer getTimer() {
 				return externalTimer;
 				return externalTimer;
 			}
 			}
 			
 			
-			public synchronized void timeElapsed(int eventID) {
-				super.timeElapsed(eventID);
+			public void timeElapsed(int eventID) {
+				synchronized (statemachine) {
+					statemachine.timeElapsed(eventID);
+					statemachine.runCycle();
+				}
 			}
 			}
 		«ENDIF»
 		«ENDIF»
 	'''
 	'''
-	
+
 }
 }

+ 20 - 181
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/EventBasedRunnableWrapper.xtend

@@ -6,6 +6,8 @@
   http://www.eclipse.org/legal/epl-v10.html
   http://www.eclipse.org/legal/epl-v10.html
   Contributors:
   Contributors:
   	Axel Terfloth - Initial contribution and API
   	Axel Terfloth - Initial contribution and API
+  	Markus Mühlbrandt - Additions
+  	
 */
 */
 
 
 package org.yakindu.sct.generator.java
 package org.yakindu.sct.generator.java
@@ -20,6 +22,7 @@ import org.yakindu.base.types.Direction
 import org.yakindu.base.types.typesystem.GenericTypeSystem
 import org.yakindu.base.types.typesystem.GenericTypeSystem
 import org.yakindu.sct.generator.core.types.ICodegenTypeSystemAccess
 import org.yakindu.sct.generator.core.types.ICodegenTypeSystemAccess
 import org.yakindu.sct.generator.java.features.EventBasedRunnableFeature
 import org.yakindu.sct.generator.java.features.EventBasedRunnableFeature
+import org.yakindu.sct.generator.java.features.CycleBasedWrapperFeature
 
 
 /**
 /**
  * Generates the runnable wrapper for the state machine. This wrapper implies event based execution semantics. 
  * Generates the runnable wrapper for the state machine. This wrapper implies event based execution semantics. 
@@ -28,6 +31,7 @@ class EventBasedRunnableWrapper {
 
 
 	@Inject protected extension GenmodelEntries
 	@Inject protected extension GenmodelEntries
 	@Inject protected extension EventBasedRunnableFeature
 	@Inject protected extension EventBasedRunnableFeature
+	@Inject protected extension CycleBasedWrapperFeature
 
 
 	@Inject protected extension Naming
 	@Inject protected extension Naming
 	@Inject protected extension Navigation
 	@Inject protected extension Navigation
@@ -41,90 +45,31 @@ class EventBasedRunnableWrapper {
 		fsa.generateFile(filename, content)
 		fsa.generateFile(filename, content)
 	}
 	}
 	
 	
-	
 	def protected content(ExecutionFlow flow, GeneratorEntry entry) '''
 	def protected content(ExecutionFlow flow, GeneratorEntry entry) '''
 		«entry.licenseText»
 		«entry.licenseText»
 		package «flow.getImplementationPackageName(entry)»;
 		package «flow.getImplementationPackageName(entry)»;
 		«flow.createImports(entry)»
 		«flow.createImports(entry)»
 		
 		
 		/**
 		/**
-		 * Runnable wrapper of «flow.statemachineClassName». This wrapper provides a thread-safe, runnable instance of the state machine.
-		 * The wrapper implements the {@link Runnable} interface and can be started in a thread by the client code. 
-		 * The run method then starts the main event processing loop for this state machine.
-		 * 
-		 * This feature is in beta state. Currently not supported are
-		 * - interface observer
-		 * - operation callbacks
+		 * Runnable wrapper of «flow.statemachineClassName». This wrapper provides a
+		 * thread-safe, runnable instance of the state machine. The wrapper implements
+		 * the {@link Runnable} interface and can be started in a thread by the client
+		 * code. The run method then starts the main event processing loop for this
+		 * state machine.
 		 * 
 		 * 
-		 * Please report bugs and issues... 
+		 * Please report bugs and issues...
 		 */
 		 */
 		
 		
-		public class «flow.eventBasedWrapperClassName(entry)» implements «flow.statemachineInterfaceName», Runnable {
+		public class «flow.eventBasedWrapperClassName(entry)» extends «flow.cycleWrapperClassName(entry)» implements Runnable {
 			
 			
 			«flow.createFieldDeclarations(entry)»
 			«flow.createFieldDeclarations(entry)»
-			«flow.interfaceAccessors»
 			«flow.timingFunctions(entry)»
 			«flow.timingFunctions(entry)»
 			
 			
 			/**
 			/**
-			 * init() will be delegated thread-safely to the wrapped state machine. 
-			 */ 
-			public void init() {
-				synchronized(statemachine) {
-					statemachine.init();
-				}
-			}
-			
-			/**
-			 * enter() will be delegated thread-safely to the wrapped state machine.  
-			 */ 
-			public void enter() {
-				synchronized(statemachine) {
-					statemachine.enter();
-				}
-			}
-			
-			/**
-			 * exit() will be delegated thread-safely to the wrapped state machine.  
-			 */ 
-			public void exit() {
-				synchronized(statemachine) {
-					statemachine.exit();
-				}
-			}
-			
-			/**
-			 * isActive() will be delegated thread-safely to the wrapped state machine.  
-			 */ 
-			public boolean isActive() {
-				synchronized(statemachine) {
-					return statemachine.isActive();
-				}
-			}
-			
-			/**
-			 * isFinal() will be delegated thread-safely to the wrapped state machine.  
-			 */ 
-			public boolean isFinal() {
-				synchronized(statemachine) {
-					return statemachine.isFinal();
-				}
-			}
-			
-			
-			/**
-			 * runCycle() will be delegated thread-safely to the wrapped state machine.  
-			 */ 
-			@Override
-			public void runCycle() {
-				synchronized (statemachine) {
-					statemachine.runCycle();
-				}
-			}
-
-			/**
-			 * This method will start the main execution loop for the state machine. 
-			 * First it will init and enter the state machine implicitly and then will start processing events 
-			 * from the event queue until the thread is interrupted. 
+			 * This method will start the main execution loop for the state machine.
+			 * First it will init and enter the state machine implicitly and then will
+			 * start processing events from the event queue until the thread is
+			 * interrupted.
 			 */
 			 */
 			@Override
 			@Override
 			public void run() {
 			public void run() {
@@ -141,54 +86,34 @@ class EventBasedRunnableWrapper {
 					} catch (InterruptedException e) {
 					} catch (InterruptedException e) {
 						terminate = true;
 						terminate = true;
 					}
 					}
-				}			
+				}
 			}
 			}
-
-			
 		}
 		}
 	'''
 	'''
 	
 	
 	def protected createImports(ExecutionFlow flow, GeneratorEntry entry) '''
 	def protected createImports(ExecutionFlow flow, GeneratorEntry entry) '''
 		import java.util.concurrent.BlockingQueue;
 		import java.util.concurrent.BlockingQueue;
 		import java.util.concurrent.LinkedBlockingQueue;
 		import java.util.concurrent.LinkedBlockingQueue;
-
-		«IF entry.createInterfaceObserver && flow.hasOutgoingEvents»
-		import java.util.LinkedList;
-		import java.util.List;
-		«ENDIF»
-		«IF flow.timed»
-			import «entry.getBasePackageName()».ITimer;
-			import «entry.getBasePackageName()».ITimerCallback;
-		«ENDIF»
 	'''
 	'''
 	
 	
 	def protected createFieldDeclarations(ExecutionFlow flow, GeneratorEntry entry) '''
 	def protected createFieldDeclarations(ExecutionFlow flow, GeneratorEntry entry) '''
-		
-		/** 
-		 * The events are queued using a blocking queue without capacity restriction. This queue holds
-		 * Runnable instances that process the events. 
-		 */
-		protected BlockingQueue<Runnable> eventQueue = new LinkedBlockingQueue<Runnable>();
-
 		/**
 		/**
-		 * The core state machine is simply wrapped and the event processing will be delegated to that state machine instance.
-		 * This instance will be created implicitly.
+		 * The events are queued using a blocking queue without capacity
+		 * restriction. This queue holds Runnable instances that process the events.
 		 */
 		 */
-		protected «flow.statemachineClassName» statemachine = new «flow.statemachineClassName»();
+		protected BlockingQueue<Runnable> eventQueue = new LinkedBlockingQueue<Runnable>();
 		
 		
 		«FOR scope : flow.interfaceScopes»
 		«FOR scope : flow.interfaceScopes»
 		/**
 		/**
 		 * Interface object for «scope.interfaceName»
 		 * Interface object for «scope.interfaceName»
 		 */		
 		 */		
-		protected «scope.interfaceName» «scope.interfaceName.asEscapedIdentifier» = new «scope.interfaceName»() {
+		protected «scope.interfaceName» «scope.interfaceName.asEscapedIdentifier» = new «scope.wrapperInterfaceName(entry)»() {
 			«scope.toImplementation(entry)»
 			«scope.toImplementation(entry)»
 		};
 		};
 		
 		
 		«ENDFOR»
 		«ENDFOR»
-		
 	'''
 	'''
 	
 	
-	
 	def protected toImplementation(InterfaceScope scope, GeneratorEntry entry) '''				
 	def protected toImplementation(InterfaceScope scope, GeneratorEntry entry) '''				
 		«FOR event : scope.eventDefinitions»
 		«FOR event : scope.eventDefinitions»
 			«IF event.direction == Direction::IN»
 			«IF event.direction == Direction::IN»
@@ -223,95 +148,11 @@ class EventBasedRunnableWrapper {
 					
 					
 				«ENDIF»
 				«ENDIF»
 			«ENDIF»
 			«ENDIF»
-			«IF event.direction == Direction::OUT»
-				public boolean isRaised«event.name.asName»() {
-					synchronized(statemachine) {
-						return statemachine.get«scope.interfaceName»().isRaised«event.name.asName»();
-					}
-				}
-				
-				«IF event.type != null && !isSame(event.type, getType(GenericTypeSystem.VOID))»
-					public «event.type.targetLanguageName» get«event.name.asName»Value() {
-						synchronized(statemachine) {
-							return statemachine.get«scope.interfaceName»().get«event.name.asName»Value();
-						}
-					}
-				«ENDIF»
-			«ENDIF»
-		«ENDFOR»
-		«FOR variable : scope.variableDefinitions»
-			public «variable.type.targetLanguageName» «variable.getter» {
-				synchronized(statemachine) {
-					return statemachine.get«scope.interfaceName»().«variable.getter»;
-				}
-			}
-			
-			«IF !variable.readonly && !variable.const»
-				public void «variable.setter»(final «variable.type.targetLanguageName» value) {
-					synchronized(statemachine) {
-						statemachine.get«scope.interfaceName»().«variable.setter»(value);
-					}
-				}
-				
-			«ENDIF»
-		«ENDFOR»
-	'''
-
-	def protected interfaceAccessors(ExecutionFlow flow) '''
-		«FOR scope : flow.interfaceScopes»
-			public «scope.interfaceName» get«scope.interfaceName»() {
-				return «scope.interfaceName.asEscapedIdentifier»;
-			}
 		«ENDFOR»
 		«ENDFOR»
 	'''
 	'''
 
 
-
 	def protected timingFunctions(ExecutionFlow flow, GeneratorEntry entry) '''
 	def protected timingFunctions(ExecutionFlow flow, GeneratorEntry entry) '''
 		«IF flow.timed»
 		«IF flow.timed»
-			/*========== TIME EVENT HANDLING ================
-			
-			/** An external timer instance is required. */
-			protected ITimer externalTimer;
-			
-			/** Internally we use a timer proxy that queues time events together with other input events. */
-			protected ITimer timerProxy = new ITimer() {
-				/** Simply delegate to external timer with a modified callback. */
-				@Override
-				public void setTimer(ITimerCallback callback, int eventID, long time,
-						boolean isPeriodic) {
-					externalTimer.setTimer(«flow.eventBasedWrapperClassName(entry)».this, eventID, time, isPeriodic);
-				}
-				
-				@Override
-				public void unsetTimer(ITimerCallback callback, int eventID) {
-					externalTimer.unsetTimer(«flow.eventBasedWrapperClassName(entry)».this, eventID);
-				}
-			};
-			
-			/**
-			 * Set the {@link ITimer} for the state machine. It must be set
-			 * externally on a timed state machine before a run cycle can be correct
-			 * executed.
-			 * 
-			 * @param timer
-			 */
-			public void setTimer(ITimer timer) {
-				synchronized(statemachine) {
-					this.externalTimer = timer;
-					/* the wrapped state machine uses timer proxy as timer */
-					statemachine.setTimer(timerProxy);
-				}
-			}
-			
-			/**
-			* Returns the currently used timer.
-			* 
-			* @return {@link ITimer}
-			*/
-			public ITimer getTimer() {
-				return externalTimer;
-			}
-			
 			public void timeElapsed(int eventID) {
 			public void timeElapsed(int eventID) {
 				eventQueue.add(new Runnable() {
 				eventQueue.add(new Runnable() {
 
 
@@ -324,8 +165,6 @@ class EventBasedRunnableWrapper {
 					}
 					}
 				});
 				});
 			}
 			}
-			
 		«ENDIF»
 		«ENDIF»
 	'''
 	'''
-	
 }
 }

+ 4 - 4
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/JavaGenerator.xtend

@@ -59,12 +59,12 @@ class JavaGenerator implements IExecutionFlowGenerator {
 		flow.generateStatemachineInterface(entry, fsa)
 		flow.generateStatemachineInterface(entry, fsa)
 		flow.generateStatemachine(entry, fsa)
 		flow.generateStatemachine(entry, fsa)
 		
 		
-		if (entry.hasFeatureEventRunnable) {
-			flow.generateEventBasedRunnableWrapper(entry, fsa)
+		if (entry.hasFeatureCycleWrapper || entry.hasFeatureEventRunnable) {
+			flow.generateCycleWrapper(entry, fsa)
 		}
 		}
 		
 		
-		if (entry.hasFeatureCycleWrapper) {
-			flow.generateCycleWrapper(entry, fsa)
+		if (entry.hasFeatureEventRunnable) {
+			flow.generateEventBasedRunnableWrapper(entry, fsa)
 		}
 		}
 	}
 	}
 }
 }

+ 2 - 2
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/Statemachine.xtend

@@ -341,7 +341,7 @@ class Statemachine {
 		protected class «scope.getInterfaceImplName» implements «scope.getInterfaceName» {
 		protected class «scope.getInterfaceImplName» implements «scope.getInterfaceName» {
 		
 		
 		«IF entry.createInterfaceObserver && scope.hasOutgoingEvents»
 		«IF entry.createInterfaceObserver && scope.hasOutgoingEvents»
-			«scope.generateListeners»
+			«scope.generateListenerSupport»
 		«ENDIF»
 		«ENDIF»
 		
 		
 		«IF scope.hasOperations»
 		«IF scope.hasOperations»
@@ -489,7 +489,7 @@ class Statemachine {
 	'''
 	'''
 	
 	
 	
 	
-	protected def generateListeners(InterfaceScope scope) '''
+	protected def generateListenerSupport(InterfaceScope scope) '''
 		private List<«scope.getInterfaceListenerName»> listeners = new LinkedList<«scope.getInterfaceListenerName»>();
 		private List<«scope.getInterfaceListenerName»> listeners = new LinkedList<«scope.getInterfaceListenerName»>();
 		
 		
 		public List<«scope.getInterfaceListenerName»> getListeners() {
 		public List<«scope.getInterfaceListenerName»> getListeners() {

+ 25 - 15
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/features/CycleBasedWrapperFeature.xtend

@@ -6,8 +6,8 @@
  * http://www.eclipse.org/legal/epl-v10.html 
  * http://www.eclipse.org/legal/epl-v10.html 
  * Contributors:
  * Contributors:
  * committers of YAKINDU - initial API and implementation
  * committers of YAKINDU - initial API and implementation
- *
-*/
+ * 
+ */
 package org.yakindu.sct.generator.java.features
 package org.yakindu.sct.generator.java.features
 
 
 import org.yakindu.sct.model.sgen.GeneratorEntry
 import org.yakindu.sct.model.sgen.GeneratorEntry
@@ -15,31 +15,41 @@ import org.yakindu.sct.generator.java.features.IJavaFeatureConstants
 import org.yakindu.sct.model.sexec.ExecutionFlow
 import org.yakindu.sct.model.sexec.ExecutionFlow
 import com.google.inject.Inject
 import com.google.inject.Inject
 import org.yakindu.sct.generator.java.Naming
 import org.yakindu.sct.generator.java.Naming
+import org.yakindu.sct.model.stext.stext.InterfaceScope
 
 
 class CycleBasedWrapperFeature {
 class CycleBasedWrapperFeature {
-	
+
 	@Inject extension Naming
 	@Inject extension Naming
-	
+
 	def getFeatureCycleWrapper(GeneratorEntry it) {
 	def getFeatureCycleWrapper(GeneratorEntry it) {
-		getFeatureConfiguration(IJavaFeatureConstants::CYCLE_BASED_SYCHRONIZED_WRAPPER);
+		getFeatureConfiguration(IJavaFeatureConstants::FEATURE_SYCHRONIZED_WRAPPER);
 	}
 	}
-	
+
 	def hasFeatureCycleWrapper(GeneratorEntry it) {
 	def hasFeatureCycleWrapper(GeneratorEntry it) {
 		featureCycleWrapper != null
 		featureCycleWrapper != null
 	}
 	}
-	
+
 	def getNamePrefix(GeneratorEntry it) {
 	def getNamePrefix(GeneratorEntry it) {
-		if (featureCycleWrapper != null) featureCycleWrapper.getParameterValue(IJavaFeatureConstants::NAME_PREFIX).stringValue
-		else ""	
+		if (featureCycleWrapper != null &&
+			featureCycleWrapper.getParameterValue(IJavaFeatureConstants::VALUE_NAME_PREFIX) != null)
+			featureCycleWrapper.getParameterValue(IJavaFeatureConstants::VALUE_NAME_PREFIX).stringValue
+		else
+			IJavaFeatureConstants::SYCHRONIZED_WRAPPER_NAME_PREFIX_DEFAULT
 	}
 	}
-	
+
 	def getNameSuffix(GeneratorEntry it) {
 	def getNameSuffix(GeneratorEntry it) {
-		if (featureCycleWrapper != null) featureCycleWrapper.getParameterValue(IJavaFeatureConstants::NAME_SUFFIX).stringValue
-		else ""	
+		if (featureCycleWrapper != null &&
+			featureCycleWrapper.getParameterValue(IJavaFeatureConstants::VALUE_NAME_PREFIX) != null)
+			featureCycleWrapper.getParameterValue(IJavaFeatureConstants::VALUE_NAME_SUFFIX).stringValue
+		else
+			IJavaFeatureConstants::SYCHRONIZED_WRAPPER_NAME_SUFFIX_DEFAULT
 	}
 	}
-	
-	
+
 	def cycleWrapperClassName(ExecutionFlow it, GeneratorEntry entry) {
 	def cycleWrapperClassName(ExecutionFlow it, GeneratorEntry entry) {
-		 entry.namePrefix + statemachineName + entry.nameSuffix 
+		entry.namePrefix + statemachineName + entry.nameSuffix
+	}
+	
+	def wrapperInterfaceName(InterfaceScope it, GeneratorEntry entry) {
+		entry.namePrefix + interfaceName + entry.nameSuffix
 	}
 	}
 }
 }

+ 19 - 14
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/features/EventBasedRunnableFeature.xtend

@@ -6,8 +6,8 @@
  * http://www.eclipse.org/legal/epl-v10.html 
  * http://www.eclipse.org/legal/epl-v10.html 
  * Contributors:
  * Contributors:
  * committers of YAKINDU - initial API and implementation
  * committers of YAKINDU - initial API and implementation
- *
-*/
+ * 
+ */
 package org.yakindu.sct.generator.java.features
 package org.yakindu.sct.generator.java.features
 
 
 import org.yakindu.sct.model.sgen.GeneratorEntry
 import org.yakindu.sct.model.sgen.GeneratorEntry
@@ -17,28 +17,33 @@ import com.google.inject.Inject
 import org.yakindu.sct.generator.java.Naming
 import org.yakindu.sct.generator.java.Naming
 
 
 class EventBasedRunnableFeature {
 class EventBasedRunnableFeature {
-	
+
 	@Inject extension Naming
 	@Inject extension Naming
-	
+
 	def getFeatureEventRunnable(GeneratorEntry it) {
 	def getFeatureEventRunnable(GeneratorEntry it) {
-		getFeatureConfiguration(IJavaFeatureConstants::EVENT_BASED_RUNNABLE_WRAPPER);
+		getFeatureConfiguration(IJavaFeatureConstants::FEATURE_RUNNABLE_WRAPPER);
 	}
 	}
-	
+
 	def hasFeatureEventRunnable(GeneratorEntry it) {
 	def hasFeatureEventRunnable(GeneratorEntry it) {
 		featureEventRunnable != null
 		featureEventRunnable != null
 	}
 	}
-	
+
 	def getNamePrefix(GeneratorEntry it) {
 	def getNamePrefix(GeneratorEntry it) {
-		if (featureEventRunnable != null) featureEventRunnable.getParameterValue(IJavaFeatureConstants::NAME_PREFIX).stringValue
-		else ""	
+		if (featureEventRunnable != null &&
+			featureEventRunnable.getParameterValue(IJavaFeatureConstants::VALUE_NAME_PREFIX) != null)
+			featureEventRunnable.getParameterValue(IJavaFeatureConstants::VALUE_NAME_PREFIX).stringValue
+		else
+			IJavaFeatureConstants::RUNNABLE_WRAPPER_NAME_PREFIX_DEFAULT
 	}
 	}
-	
+
 	def getNameSuffix(GeneratorEntry it) {
 	def getNameSuffix(GeneratorEntry it) {
-		if (featureEventRunnable != null) featureEventRunnable.getParameterValue(IJavaFeatureConstants::NAME_SUFFIX).stringValue
-		else ""	
+		if (featureEventRunnable != null)
+			featureEventRunnable.getParameterValue(IJavaFeatureConstants::VALUE_NAME_SUFFIX).stringValue
+		else
+			IJavaFeatureConstants::RUNNABLE_WRAPPER_NAME_SUFFIX_DEFAULT
 	}
 	}
-	
+
 	def eventBasedWrapperClassName(ExecutionFlow it, GeneratorEntry entry) {
 	def eventBasedWrapperClassName(ExecutionFlow it, GeneratorEntry entry) {
-		 entry.namePrefix + statemachineName + entry.nameSuffix 
+		entry.namePrefix + statemachineName + entry.nameSuffix
 	}
 	}
 }
 }

+ 9 - 4
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/features/IJavaFeatureConstants.java

@@ -44,16 +44,21 @@ public interface IJavaFeatureConstants {
 	
 	
 	/* Constants related to the RunnableWrapper feature */
 	/* Constants related to the RunnableWrapper feature */
 	
 	
-	public static final String EVENT_BASED_RUNNABLE_WRAPPER = "EventBasedRunnableWrapper";
+	public static final String FEATURE_RUNNABLE_WRAPPER = "RunnableWrapper";
 	
 	
-	public static final String NAME_PREFIX = "namePrefix";
+	public static final String RUNNABLE_WRAPPER_NAME_PREFIX_DEFAULT = "";
 	
 	
-	public static final String NAME_SUFFIX = "nameSuffix";
+	public static final String RUNNABLE_WRAPPER_NAME_SUFFIX_DEFAULT = "StatemachineRunnable";
 	
 	
-	public static final String CYCLE_BASED_SYCHRONIZED_WRAPPER = "CycleBasedSynchronizedWrapper";
+	public static final String FEATURE_SYCHRONIZED_WRAPPER = "SynchronizedWrapper";
 	
 	
+	public static final String SYCHRONIZED_WRAPPER_NAME_PREFIX_DEFAULT = "";
 	
 	
+	public static final String SYCHRONIZED_WRAPPER_NAME_SUFFIX_DEFAULT = "SynchronizedStatemachine";
 	
 	
+	public static final String VALUE_NAME_PREFIX = "namePrefix";
+	
+	public static final String VALUE_NAME_SUFFIX = "nameSuffix";
 	
 	
 	public static final String[] JAVA_KEYWORDS = { "abstract", "assert",
 	public static final String[] JAVA_KEYWORDS = { "abstract", "assert",
 		"boolean", "break", "byte", "case", "catch", "char", "class",
 		"boolean", "break", "byte", "case", "catch", "char", "class",

+ 12 - 4
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/features/JavaFeatureValueProvider.java

@@ -42,10 +42,18 @@ public class JavaFeatureValueProvider extends AbstractDefaultFeatureValueProvide
 			parameterValue.setValue("org.yakindu.sct");
 			parameterValue.setValue("org.yakindu.sct");
 		} else if (parameterValue.getParameter().getName().equals(IMPLEMENTATION_SUFFIX)) {
 		} else if (parameterValue.getParameter().getName().equals(IMPLEMENTATION_SUFFIX)) {
 			parameterValue.setValue("impl");
 			parameterValue.setValue("impl");
-		} else if (parameterValue.getParameter().getName().equals(NAME_PREFIX)) {
-			parameterValue.setValue("Runnable");
-		} else if (parameterValue.getParameter().getName().equals(NAME_SUFFIX)) {
-			parameterValue.setValue("");
+		} else if (featureType.getName().equals(FEATURE_RUNNABLE_WRAPPER)) {
+			if (parameterValue.getParameter().getName().equals(VALUE_NAME_PREFIX)) {
+				parameterValue.setValue(RUNNABLE_WRAPPER_NAME_PREFIX_DEFAULT);
+			} else if (parameterValue.getParameter().getName().equals(VALUE_NAME_SUFFIX)) {
+				parameterValue.setValue(RUNNABLE_WRAPPER_NAME_SUFFIX_DEFAULT);
+			}
+		} else if (featureType.getName().equals(FEATURE_SYCHRONIZED_WRAPPER)) {
+			if (parameterValue.getParameter().getName().equals(VALUE_NAME_PREFIX)) {
+				parameterValue.setValue(SYCHRONIZED_WRAPPER_NAME_PREFIX_DEFAULT);
+			} else if (parameterValue.getParameter().getName().equals(VALUE_NAME_SUFFIX)) {
+				parameterValue.setValue(SYCHRONIZED_WRAPPER_NAME_SUFFIX_DEFAULT);
+			}
 		}
 		}
 	}
 	}
 
 

+ 10 - 0
test-plugins/org.yakindu.sct.generator.java.test/src-gen/org/yakindu/scr/TimerService.java

@@ -4,6 +4,8 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.Timer;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.TimerTask;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 
 /**
 /**
  * Default timer service implementation.
  * Default timer service implementation.
@@ -15,6 +17,8 @@ public class TimerService implements ITimer {
 	
 	
 	private final List<TimeEventTask> timerTaskList = new ArrayList<TimeEventTask>();
 	private final List<TimeEventTask> timerTaskList = new ArrayList<TimeEventTask>();
 	
 	
+	private final Lock lock = new ReentrantLock();
+	
 	/**
 	/**
 	 * Timer task that reflects a time event. It's internally used by
 	 * Timer task that reflects a time event. It's internally used by
 	 * {@link TimerService}.
 	 * {@link TimerService}.
@@ -60,6 +64,7 @@ public class TimerService implements ITimer {
 	
 	
 		// Create a new TimerTask for given event and store it.
 		// Create a new TimerTask for given event and store it.
 		TimeEventTask timerTask = new TimeEventTask(callback, eventID);
 		TimeEventTask timerTask = new TimeEventTask(callback, eventID);
+		lock.lock();
 		timerTaskList.add(timerTask);
 		timerTaskList.add(timerTask);
 	
 	
 		// start scheduling the timer
 		// start scheduling the timer
@@ -68,15 +73,18 @@ public class TimerService implements ITimer {
 		} else {
 		} else {
 			timer.schedule(timerTask, time);
 			timer.schedule(timerTask, time);
 		}
 		}
+		lock.unlock();
 	}
 	}
 	
 	
 	public void unsetTimer(ITimerCallback callback, int eventID) {
 	public void unsetTimer(ITimerCallback callback, int eventID) {
+		lock.lock();
 		int index = timerTaskList.indexOf(new TimeEventTask(callback, eventID));
 		int index = timerTaskList.indexOf(new TimeEventTask(callback, eventID));
 		if (index != -1) {
 		if (index != -1) {
 			timerTaskList.get(index).cancel();
 			timerTaskList.get(index).cancel();
 			timer.purge();
 			timer.purge();
 			timerTaskList.remove(index);
 			timerTaskList.remove(index);
 		}
 		}
+		lock.unlock();
 	}
 	}
 	
 	
 	/**
 	/**
@@ -84,8 +92,10 @@ public class TimerService implements ITimer {
 	 * memory resources.
 	 * memory resources.
 	 */
 	 */
 	public void cancel() {
 	public void cancel() {
+		lock.lock();
 		timer.cancel();
 		timer.cancel();
 		timer.purge();
 		timer.purge();
+		lock.unlock();
 	}
 	}
 }
 }