Преглед изворни кода

Reworked relative include path computation.

Thomas Kutz пре 9 година
родитељ
комит
58da854b99

+ 0 - 87
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/ArtifactLocationProvider.java

@@ -1,87 +0,0 @@
-package org.yakindu.sct.generator.c;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.emf.common.util.URI;
-import org.yakindu.sct.generator.core.filesystem.ISCTFileSystemAccess;
-
-public class ArtifactLocationProvider {
-
-	private ISCTFileSystemAccess sctFsa;
-
-	public static class Artifact {
-		
-		private String outputName;
-		private String name;
-		
-		public Artifact(String name, String outputConfigName) {
-			this.name = name;
-			this.outputName = outputConfigName;
-		}
-
-		public String getName() {
-			return name;
-		}
-
-		public String getOutputName() {
-			return outputName;
-		}
-	}
-	
-	public ArtifactLocationProvider() {}
-	
-	public ArtifactLocationProvider(ISCTFileSystemAccess sctFsa) {
-		this.sctFsa = sctFsa;
-	}
-	
-	protected List<Artifact> generationArtifacts = new ArrayList<Artifact>();
-	
-	public void addArtifact(String artifactName, String outputConfigName) {
-		generationArtifacts.add(new Artifact(artifactName, outputConfigName));
-	}
-
-	protected URI getURI(String artifactName) {
-		for (Artifact artifact : generationArtifacts) {
-			if (artifact.getName().equals(artifactName)) {
-				return getURI(artifact);
-			}
-		}
-		return null;
-	}
-
-	protected URI getURI(Artifact artifact) {
-		if (sctFsa != null) {
-			return sctFsa.getURI(artifact.getName(), artifact.getOutputName());
-		}
-		return null;
-	}
-	
-	public String getRelativePath(String target, String baseArtifactName) {
-		URI baseUri = getURI(baseArtifactName);
-		if (baseUri == null) {
-			// throw new IllegalArgumentException("Artifact location for "+baseArtifactName+" not configured");
-			return target;
-		}
-		
-		Path targetPath = new Path(target);
-		if (targetPath.isAbsolute()) {
-			return relativePath(target, baseUri.toFileString());
-		}
-		
-		URI absUri = getURI(target);
-		if (absUri != null) {
-			return relativePath(absUri.toFileString(), baseUri.toFileString());
-		}
-		// throw new IllegalArgumentException("Artifact location for "+target+" not configured");
-		return target;
-	}
-	
-	protected String relativePath(String absolute, String base) {
-		IPath basePath = new Path(base);
-		IPath absPath = new Path(absolute);
-		return absPath.makeRelativeTo(basePath).toOSString();
-	}
-}

+ 20 - 1
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/CCodeGenerator.java

@@ -44,13 +44,26 @@ public class CCodeGenerator extends GenericJavaBasedGenerator {
 	@Inject
 	private CGenerator delegate;
 	
+	@Inject
+	private IGenArtifactConfigurations artifactConfigs;
+	
+	@Override
+	protected void prepareGenerator(GeneratorEntry entry) {
+		super.prepareGenerator(entry);
+		initGenArtifactConfigurations();
+	}
+
+	protected void initGenArtifactConfigurations() {
+		artifactConfigs.setFileSystemAccess(sctFsa);
+	}
+	
 	@Override
 	public void runGenerator(Statechart statechart, GeneratorEntry entry) {
 		ExecutionFlow flow = createExecutionFlow(statechart, entry);
 		if (debugFeatureHelper.isDumpSexec(entry)) {
 			dumpSexec(entry, flow);
 		}
-		delegate.generate(flow, entry, sctFsa.getIFileSystemAccess(), new ArtifactLocationProvider(sctFsa));
+		delegate.generate(flow, entry, sctFsa.getIFileSystemAccess(), artifactConfigs);
 	}
 
 	@Override
@@ -63,6 +76,12 @@ public class CCodeGenerator extends GenericJavaBasedGenerator {
 				binder.bind(GeneratorEntry.class).toInstance(entry);
 				binder.bind(INamingService.class).to(CNamingService.class);
 				binder.bind(ICodegenTypeSystemAccess.class).to(CTypeSystemAccess.class);
+				
+				binder.bind(IGenArtifactConfigurations.class).to(GenArtifactConfigurations.class);
+				// default binding to ensure consistency of already used API
+				binder.bind(IGenArtifactConfigurations.class)
+						.annotatedWith(Names.named(IGenArtifactConfigurations.DEFAULT))
+						.toInstance(GenArtifactConfigurations.DEFAULT);
 
 				// Enable generation of trace steps in case the Tracing feature
 				// is specified and at least one of enter/exit states is

+ 30 - 19
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/CGenerator.xtend

@@ -11,11 +11,13 @@
 package org.yakindu.sct.generator.c
 
 import com.google.inject.Inject
+import com.google.inject.name.Named
 import org.eclipse.xtext.generator.IFileSystemAccess
 import org.yakindu.sct.generator.core.impl.IExecutionFlowGenerator
 import org.yakindu.sct.model.sexec.ExecutionFlow
 import org.yakindu.sct.model.sgen.GeneratorEntry
-import org.yakindu.sct.model.sgraph.Statechart
+import org.yakindu.sct.generator.core.library.IOutletFeatureHelper
+import org.yakindu.sct.generator.c.GenArtifactConfigurations.GenArtifactConfiguration
 
 /**
  * This is the C code generators main class. 
@@ -24,39 +26,48 @@ import org.yakindu.sct.model.sgraph.Statechart
  */
 class CGenerator implements IExecutionFlowGenerator {
 	 
-	@Inject extension Types
-	@Inject extension StatemachineHeader
-	@Inject extension StatemachineSource
-	@Inject extension StatemachineRequiredHeader
+	@Inject extension Types types
+	@Inject extension StatemachineHeader statemachineHeader
+	@Inject extension StatemachineSource statemachineSource
+	@Inject extension StatemachineRequiredHeader statemachineRequiredHeader
 	@Inject extension Navigation
 	@Inject extension GenmodelEntries
 	@Inject extension Naming
 	
+	@Inject IOutletFeatureHelper outletFeatureHelper
+
+	@Inject @Named(IGenArtifactConfigurations.DEFAULT)
+	IGenArtifactConfigurations defaultConfigs
+	
 	/**
 	 * @Deprecated use {@link #generate(ExecutionFlow, GeneratorEntry, IFileSystemAccess, ArtifactLocationProvider)} instead
 	 */
 	@Deprecated
 	override generate(ExecutionFlow flow, GeneratorEntry entry, IFileSystemAccess fsa) {
-		generate(flow, entry, fsa, new ArtifactLocationProvider())
+		generate(flow, entry, fsa, defaultConfigs)
 	}
 	
-	def generate(ExecutionFlow flow, GeneratorEntry entry, IFileSystemAccess fsa, ArtifactLocationProvider locations) {
-		initArtifactLocations(flow, entry, locations)
-		
-		flow.generateTypesH(flow.sourceElement as Statechart, fsa, entry)
-		flow.generateStatemachineHeader(flow.sourceElement as Statechart, fsa, entry, locations)
-		if (flow.timed || !flow.operations.empty || entry.tracingEnterState || entry.tracingExitState) {
-			flow.generateStatemachineRequiredHeader(flow.sourceElement as Statechart, fsa, entry)
+	def generate(ExecutionFlow flow, GeneratorEntry entry, IFileSystemAccess fsa, IGenArtifactConfigurations locations) {
+		initGenerationArtifacts(flow, entry, locations)
+		generateArtifacts(flow, entry, fsa, locations);
+	}
+	
+	def generateArtifacts(ExecutionFlow flow, GeneratorEntry entry, IFileSystemAccess fsa, IGenArtifactConfigurations locations) {
+		for (GenArtifactConfiguration a : locations.configurations) {
+			fsa.generateFile(a.getName, a.getOutputName, a.getContentTemplate.content(flow, entry, locations))
 		}
-		flow.generateStatemachineSource(flow.sourceElement as Statechart, fsa, entry)
 	}
 	
-	def protected initArtifactLocations(ExecutionFlow flow, GeneratorEntry entry, ArtifactLocationProvider locations) {
-		locations.addArtifact(flow.typesModule.h, IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT)
-		locations.addArtifact(flow.module.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT)
-		locations.addArtifact(flow.module.c, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT)
+	def protected initGenerationArtifacts(ExecutionFlow flow, GeneratorEntry entry, IGenArtifactConfigurations locations) {
+		if (outletFeatureHelper.getLibraryTargetFolderValue(entry) != null) {
+			locations.configure(flow.typesModule.h, IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT, types)
+		} else {
+			locations.configure(flow.typesModule.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, types)
+		}
+		locations.configure(flow.module.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, statemachineHeader)
+		locations.configure(flow.module.c, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, statemachineSource)
 		if (flow.timed || !flow.operations.empty || entry.tracingEnterState || entry.tracingExitState) {
-			locations.addArtifact(flow.module.client.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT)
+			locations.configure(flow.module.client.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, statemachineRequiredHeader)
 		}
 	}
 	

+ 143 - 0
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/GenArtifactConfigurations.java

@@ -0,0 +1,143 @@
+/**
+ * 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.generator.c;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.util.URI;
+import org.yakindu.sct.generator.core.filesystem.ISCTFileSystemAccess;
+
+/**
+ * 
+ * @author thomas kutz - Initial API and contribution
+ *
+ */
+public class GenArtifactConfigurations implements IGenArtifactConfigurations {
+
+	private static final String MSG_FSA_NOT_CONFIGURED = "File system access needs to be configured before artifact locations can be computed.";
+	private static final String MSG_LOCATION_NOT_FOUND = "Artifact location for {0} not configured";
+	private ISCTFileSystemAccess sctFsa;
+
+	public static class GenArtifactConfiguration {
+		
+		private String outputName;
+		private String name;
+		private IContentTemplate contentTemplate;
+		
+		public GenArtifactConfiguration(String name, String outputConfigName, IContentTemplate contentTemplate) {
+			this.name = name;
+			this.outputName = outputConfigName;
+			this.contentTemplate = contentTemplate;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public String getOutputName() {
+			return outputName;
+		}
+		
+		public IContentTemplate getContentTemplate() {
+			return contentTemplate;
+		}
+	}
+	
+	/**
+	 * Default instance which does not compute any relative paths and hence does not need to be configured in any way.
+	 * This is useful when an API needs to be served but relative path computation is not relevant.
+	 */
+	public static final IGenArtifactConfigurations DEFAULT = new GenArtifactConfigurations() {
+		/**
+		 * As default behavior, this will always return the target path/artifact instead of a relative path.
+		 */
+		public String relativeTo(String target, String fromArtifact) {
+			return target;
+		};
+	};
+	
+	@Override
+	public void setFileSystemAccess(ISCTFileSystemAccess sctFsa) {
+		this.sctFsa = sctFsa;
+	}
+	
+	protected List<GenArtifactConfiguration> generationArtifacts = new ArrayList<GenArtifactConfiguration>();
+	
+	@Override
+	public List<GenArtifactConfiguration> getConfigurations() {
+		return generationArtifacts;
+	}
+	
+	@Override
+	public void configure(String artifactName, String outputConfigName, IContentTemplate contentTemplate) {
+		generationArtifacts.add(new GenArtifactConfiguration(artifactName, outputConfigName, contentTemplate));
+	}
+
+	protected URI getOutputFolder(String artifactName) {
+		checkFSA();
+		for (GenArtifactConfiguration artifact : generationArtifacts) {
+			if (artifact.getName().equals(artifactName)) {
+				return sctFsa.getURI("", artifact.getOutputName());
+			}
+		}
+		return null;
+	}
+	
+	protected URI getURI(String artifactName) {
+		checkFSA();
+		for (GenArtifactConfiguration artifact : generationArtifacts) {
+			if (artifact.getName().equals(artifactName)) {
+				return sctFsa.getURI(artifact.getName(), artifact.getOutputName());
+			}
+		}
+		return null;
+	}
+
+	private void checkFSA() {
+		if (sctFsa == null)
+			throw new IllegalStateException(MSG_FSA_NOT_CONFIGURED);
+	}
+	
+	/**
+	 * @param target either target artifact name or absolute target path which will be transformed to a relative path based on <code>fromArtifact</code> location
+	 * @param fromArtifact artifact name whose location is used as base for relative path computation
+	 * @return the relative path from <code>fromArtifact</code> to <code>toTarget</code>
+	 */
+	@Override
+	public String relativeTo(String target, String fromArtifact) {
+		URI baseUri = getOutputFolder(fromArtifact);
+		if (baseUri == null) {
+			throw new IllegalArgumentException(MessageFormat.format(MSG_LOCATION_NOT_FOUND, fromArtifact));
+		}
+		
+		Path targetPath = new Path(target);
+		if (targetPath.isAbsolute()) {
+			return relativePath(target, baseUri.toFileString());
+		}
+		
+		URI absUri = getURI(target);
+		if (absUri != null) {
+			return relativePath(absUri.toFileString(), baseUri.toFileString());
+		}
+		throw new IllegalArgumentException(MessageFormat.format(MSG_LOCATION_NOT_FOUND, target));
+	}
+	
+	protected String relativePath(String to, String from) {
+		IPath basePath = new Path(from);
+		IPath toPath = new Path(to);
+		return toPath.makeRelativeTo(basePath).toOSString();
+	}
+
+}

+ 9 - 0
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/IContentTemplate.java

@@ -0,0 +1,9 @@
+package org.yakindu.sct.generator.c;
+
+import org.yakindu.sct.model.sexec.ExecutionFlow;
+import org.yakindu.sct.model.sgen.GeneratorEntry;
+
+public interface IContentTemplate {
+
+	String content(ExecutionFlow flow, GeneratorEntry entry, IGenArtifactConfigurations locations);
+}

+ 57 - 0
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/IGenArtifactConfigurations.java

@@ -0,0 +1,57 @@
+/**
+ * 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.generator.c;
+
+import java.util.List;
+
+import org.yakindu.sct.generator.c.GenArtifactConfigurations.GenArtifactConfiguration;
+import org.yakindu.sct.generator.core.filesystem.ISCTFileSystemAccess;
+
+/**
+ * Holds the configuration of generation artifacts. A configuration comprises
+ * the artifact's name, its output configuration name and a template defining
+ * the artifact's contents.
+ * 
+ * @author thomas kutz - Initial API and contribution
+ *
+ */
+public interface IGenArtifactConfigurations {
+
+	/**
+	 * Used as key in Guice to mark a default configuration instance
+	 */
+	String DEFAULT = "DefaultGenArtifactConfigurations";
+
+	/**
+	 * A file system access is needed to define the target location of a
+	 * generation artifact. Without this, relative paths via
+	 * {@link getRelativePath(String, String)} will not work.
+	 */
+	void setFileSystemAccess(ISCTFileSystemAccess sctFsa);
+
+	/**
+	 * Adds a configuration for a generation artifact.
+	 */
+	void configure(String artifactName, String outputConfigName, IContentTemplate contentTemplate);
+
+	/**
+	 * @return all stored configurations
+	 */
+	List<GenArtifactConfiguration> getConfigurations();
+
+	/**
+	 * Computes the relative path from a base artifact to a target which can be
+	 * an artifact name or an absolute path. For the former case, the artifact
+	 * configuration needs to be stored beforehand.
+	 */
+	String relativeTo(String target, String fromArtifact);
+
+}

+ 12 - 29
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/StatemachineHeader.xtend

@@ -11,7 +11,7 @@
 package org.yakindu.sct.generator.c
 
 import com.google.inject.Inject
-import org.eclipse.xtext.generator.IFileSystemAccess
+import com.google.inject.name.Named
 import org.yakindu.base.types.Declaration
 import org.yakindu.base.types.Direction
 import org.yakindu.sct.generator.core.types.ICodegenTypeSystemAccess
@@ -20,7 +20,6 @@ import org.yakindu.sct.model.sexec.TimeEvent
 import org.yakindu.sct.model.sexec.naming.INamingService
 import org.yakindu.sct.model.sgen.GeneratorEntry
 import org.yakindu.sct.model.sgraph.Scope
-import org.yakindu.sct.model.sgraph.Statechart
 import org.yakindu.sct.model.stext.stext.EventDefinition
 import org.yakindu.sct.model.stext.stext.InterfaceScope
 import org.yakindu.sct.model.stext.stext.InternalScope
@@ -29,7 +28,7 @@ import org.yakindu.sct.model.stext.stext.VariableDefinition
 
 import static org.eclipse.xtext.util.Strings.*
 
-class StatemachineHeader {
+class StatemachineHeader implements IContentTemplate {
 
 	@Inject extension Naming cNaming
 	@Inject extension Navigation
@@ -37,34 +36,18 @@ class StatemachineHeader {
 	@Inject extension GenmodelEntries
 	@Inject extension INamingService
 	
-	/**
-	 * @Deprecated use {@link #generateStatemachineHeader(ExecutionFlow, Statechart, IFileSystemAccess, GeneratorEntry, ArtifactLocationProvider)} instead
-	 */
-	@Deprecated
-	def generateStatemachineHeader(ExecutionFlow flow, Statechart sc, IFileSystemAccess fsa, GeneratorEntry entry) {
-		generateStatemachineHeader(flow, sc, fsa, entry, new ArtifactLocationProvider())
-	}
+	@Inject @Named(IGenArtifactConfigurations.DEFAULT)
+	IGenArtifactConfigurations defaultConfigs
 	
-	def generateStatemachineHeader(ExecutionFlow flow, Statechart sc, IFileSystemAccess fsa, GeneratorEntry entry, ArtifactLocationProvider locations) {
-		flow.initializeNamingService
-		fsa.generateFile(flow.module.h, flow.generateStatemachineHeaderContents(entry, locations))
-	}
-	
-	/**
-	 * @Deprecated use {@link #generateStatemachineHeaderContents(ExecutionFlow, GeneratorEntry, ArtifactLocationProvider)} instead
-	 */
-	@Deprecated
-	def generateStatemachineHeaderContents(ExecutionFlow it, GeneratorEntry entry) {
-		generateStatemachineHeaderContents(it, entry, new ArtifactLocationProvider())
-	}
-
-	def generateStatemachineHeaderContents(ExecutionFlow it, GeneratorEntry entry, ArtifactLocationProvider locations) '''
+	override content(ExecutionFlow it, GeneratorEntry entry , IGenArtifactConfigurations artifactConfigs) {
+		initializeNamingService
+	'''
 		«entry.licenseText»
 		
 		#ifndef «module.define»_H_
 		#define «module.define»_H_
 		
-		«includes(locations)»
+		«includes(artifactConfigs)»
 				
 		#ifdef __cplusplus
 		extern "C" { 
@@ -124,17 +107,17 @@ class StatemachineHeader {
 		
 		#endif /* «module.define»_H_ */
 	'''
-
+	}
 	/**
 	 * @Deprecated use {@link #includes(ExecutionFlow, ArtifactLocationProvider)} instead
 	 */
 	@Deprecated
 	def includes(ExecutionFlow it) {
-		includes(it, new ArtifactLocationProvider())
+		includes(it, defaultConfigs)
 	}
 
-	def includes(ExecutionFlow it, ArtifactLocationProvider locations) '''
-		#include "«locations.getRelativePath(typesModule.h, module.h)»"
+	def includes(ExecutionFlow it, extension IGenArtifactConfigurations artifactConfigs) '''
+		#include "«(typesModule.h).relativeTo(module.h)»"
 	'''
 	
 	def statesEnumDecl(ExecutionFlow it) '''

+ 80 - 86
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/StatemachineRequiredHeader.xtend

@@ -11,17 +11,15 @@
 package org.yakindu.sct.generator.c
 
 import com.google.inject.Inject
-import org.eclipse.xtext.generator.IFileSystemAccess
 import org.yakindu.base.types.Declaration
 import org.yakindu.sct.generator.core.types.ICodegenTypeSystemAccess
 import org.yakindu.sct.model.sexec.ExecutionFlow
 import org.yakindu.sct.model.sexec.naming.INamingService
 import org.yakindu.sct.model.sgen.GeneratorEntry
-import org.yakindu.sct.model.sgraph.Statechart
 import org.yakindu.sct.model.stext.stext.OperationDefinition
 import org.yakindu.sct.model.stext.stext.StatechartScope
 
-class StatemachineRequiredHeader {
+class StatemachineRequiredHeader implements IContentTemplate {
 
 	@Inject extension Naming cNaming
 	@Inject extension Navigation
@@ -29,94 +27,90 @@ class StatemachineRequiredHeader {
 	@Inject extension GenmodelEntries
 	@Inject extension INamingService
 	
-	def generateStatemachineRequiredHeader(ExecutionFlow flow, Statechart sc, IFileSystemAccess fsa, GeneratorEntry entry) {
-		 fsa.generateFile(flow.module.client.h, flow.statemachineRequiredHeaderContents(entry) )
-	}
-	
-	def statemachineRequiredHeaderContents(ExecutionFlow it, GeneratorEntry entry) '''
-			«entry.licenseText»
-			
-			#ifndef «module.client.define»_H_
-			#define «module.client.define»_H_
+	override content(ExecutionFlow it, GeneratorEntry entry, extension IGenArtifactConfigurations artifactConfigs) '''
+		«entry.licenseText»
+		
+		#ifndef «module.client.define»_H_
+		#define «module.client.define»_H_
 
-			#include "«typesModule.h»"
-			«IF timed || operations.size > 0»#include "«module.h»"«ENDIF»
+		#include "«(typesModule.h).relativeTo(module.client.h)»"
+		«IF timed || operations.size > 0»#include "«(module.h).relativeTo(module.client.h)»"«ENDIF»
 
-			#ifdef __cplusplus
-			extern "C"
-			{
-			#endif 
-			
-			/*! \file This header defines prototypes for all functions that are required by the state machine implementation.
+		#ifdef __cplusplus
+		extern "C"
+		{
+		#endif 
+		
+		/*! \file This header defines prototypes for all functions that are required by the state machine implementation.
+		
+		«IF timed»
+			This is a state machine uses time events which require access to a timing service. Thus the function prototypes:
+				- «type.toFirstLower»_setTimer and
+				- «type.toFirstLower»_unsetTimer
+			are defined.
 			
-			«IF timed»
-				This is a state machine uses time events which require access to a timing service. Thus the function prototypes:
-					- «type.toFirstLower»_setTimer and
-					- «type.toFirstLower»_unsetTimer
-				are defined.
-				
-			«ENDIF»
-			«IF operations.size > 0»
-				This state machine makes use of operations declared in the state machines interface or internal scopes. Thus the function prototypes:
-					«FOR o : operations»
-					- «o.asFunction»
-					«ENDFOR»
-				are defined.
-				
-			«ENDIF»
-			These functions will be called during a 'run to completion step' (runCycle) of the statechart. 
-			There are some constraints that have to be considered for the implementation of these functions:
-				- never call the statechart API functions from within these functions.
-				- make sure that the execution time is as short as possible.
-			 
-			*/
-			«FOR s : it.scopes »
-			«s.scopeFunctionPrototypes»
+		«ENDIF»
+		«IF operations.size > 0»
+			This state machine makes use of operations declared in the state machines interface or internal scopes. Thus the function prototypes:
+				«FOR o : operations»
+				- «o.asFunction»
+				«ENDFOR»
+			are defined.
 			
-			«ENDFOR»
-			«IF timed»
-			/*!
-			 * This is a timed state machine that requires timer services
-			 */ 
-			
-			/*! This function has to set up timers for the time events that are required by the state machine. */
-			/*! 
-				This function will be called for each time event that is relevant for a state when a state will be entered.
-				\param evid An unique identifier of the event.
-				\time_ms The time in milli seconds
-				\periodic Indicates the the time event must be raised periodically until the timer is unset 
-			*/
-			extern void «type.toFirstLower»_setTimer(«scHandleDecl», const sc_eventid evid, const sc_integer time_ms, const sc_boolean periodic);
+		«ENDIF»
+		These functions will be called during a 'run to completion step' (runCycle) of the statechart. 
+		There are some constraints that have to be considered for the implementation of these functions:
+			- never call the statechart API functions from within these functions.
+			- make sure that the execution time is as short as possible.
+		 
+		*/
+		«FOR s : it.scopes »
+		«s.scopeFunctionPrototypes»
+		
+		«ENDFOR»
+		«IF timed»
+		/*!
+		 * This is a timed state machine that requires timer services
+		 */ 
+		
+		/*! This function has to set up timers for the time events that are required by the state machine. */
+		/*! 
+			This function will be called for each time event that is relevant for a state when a state will be entered.
+			\param evid An unique identifier of the event.
+			\time_ms The time in milli seconds
+			\periodic Indicates the the time event must be raised periodically until the timer is unset 
+		*/
+		extern void «type.toFirstLower»_setTimer(«scHandleDecl», const sc_eventid evid, const sc_integer time_ms, const sc_boolean periodic);
 
-			/*! This function has to unset timers for the time events that are required by the state machine. */
-			/*! 
-				This function will be called for each time event taht is relevant for a state when a state will be left.
-				\param evid An unique identifier of the event.
-			*/
-			extern void «type.toFirstLower»_unsetTimer(«scHandleDecl», const sc_eventid evid);
-			«ENDIF»
-			
-			
-			«IF entry.tracingEnterState || entry.tracingExitState»
-			/*!
-			 * Tracing callback functions
-			 */
-			«IF entry.tracingEnterState»
-				/*! This function is called when a state is entered. */
-				extern void «type.toFirstLower»_stateEntered(«scHandleDecl», const «statesEnumType» state);
-			«ENDIF»
-			
-			«IF entry.tracingExitState»
-				/*! This function is called when a state is exited. */
-				extern void «type.toFirstLower»_stateExited(«scHandleDecl», const «statesEnumType» state);
-			«ENDIF»
-			«ENDIF»
-			
-			#ifdef __cplusplus
-			}
-			#endif 
-			
-			#endif /* «module.client.define»_H_ */
+		/*! This function has to unset timers for the time events that are required by the state machine. */
+		/*! 
+			This function will be called for each time event taht is relevant for a state when a state will be left.
+			\param evid An unique identifier of the event.
+		*/
+		extern void «type.toFirstLower»_unsetTimer(«scHandleDecl», const sc_eventid evid);
+		«ENDIF»
+		
+		
+		«IF entry.tracingEnterState || entry.tracingExitState»
+		/*!
+		 * Tracing callback functions
+		 */
+		«IF entry.tracingEnterState»
+			/*! This function is called when a state is entered. */
+			extern void «type.toFirstLower»_stateEntered(«scHandleDecl», const «statesEnumType» state);
+		«ENDIF»
+		
+		«IF entry.tracingExitState»
+			/*! This function is called when a state is exited. */
+			extern void «type.toFirstLower»_stateExited(«scHandleDecl», const «statesEnumType» state);
+		«ENDIF»
+		«ENDIF»
+		
+		#ifdef __cplusplus
+		}
+		#endif 
+		
+		#endif /* «module.client.define»_H_ */
 	'''
 	
 	

+ 10 - 16
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/StatemachineSource.xtend

@@ -12,7 +12,7 @@ package org.yakindu.sct.generator.c
 
 import com.google.inject.Inject
 import java.util.List
-import org.eclipse.xtext.generator.IFileSystemAccess
+import org.eclipse.xtext.util.Strings
 import org.yakindu.sct.generator.core.types.ICodegenTypeSystemAccess
 import org.yakindu.sct.model.sexec.Check
 import org.yakindu.sct.model.sexec.ExecutionFlow
@@ -20,12 +20,10 @@ import org.yakindu.sct.model.sexec.Step
 import org.yakindu.sct.model.sexec.extensions.StateVectorExtensions
 import org.yakindu.sct.model.sexec.naming.INamingService
 import org.yakindu.sct.model.sgen.GeneratorEntry
-import org.yakindu.sct.model.sgraph.Statechart
-import org.yakindu.sct.model.stext.stext.VariableDefinition
 import org.yakindu.sct.model.stext.stext.StatechartScope
-import org.eclipse.xtext.util.Strings
+import org.yakindu.sct.model.stext.stext.VariableDefinition
 
-class StatemachineSource {
+class StatemachineSource implements IContentTemplate {
 	
 	@Inject extension Naming
 	@Inject extension GenmodelEntries
@@ -36,22 +34,17 @@ class StatemachineSource {
 	@Inject extension ConstantInitializationResolver
 	@Inject protected extension StateVectorExtensions
 	
-	def generateStatemachineSource(ExecutionFlow flow, Statechart sc, IFileSystemAccess fsa, GeneratorEntry entry) {
-		flow.initializeNamingService
-		var content = flow.generateStatemachineSourceContents(entry)
-		var target = flow.module.c
-		fsa.generateFile(target , content)
-	}
-	
-	def generateStatemachineSourceContents(ExecutionFlow it, GeneratorEntry entry) '''
+	override content(ExecutionFlow it, GeneratorEntry entry, extension IGenArtifactConfigurations artifactConfigs) { 
+		initializeNamingService
+	'''
 		«entry.licenseText»
 		
 		#include <stdlib.h>
 		#include <string.h>
-		#include "«typesModule.h»"
-		#include "«module.h»"
+		#include "«(typesModule.h).relativeTo(module.c)»"
+		#include "«(module.h).relativeTo(module.c)»"
 		«IF timed || !it.operations.empty»
-			#include "«module.client.h»"
+			#include "«(module.client.h).relativeTo(module.c)»"
 		«ENDIF»
 		/*! \file Implementation of the state machine '«name»'
 		*/
@@ -84,6 +77,7 @@ class StatemachineSource {
 		
 		«functionImplementations»
 	'''
+	}
 	
 	def initFunction(ExecutionFlow it) '''
 		void «functionPrefix»init(«scHandleDecl»)

+ 2 - 18
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/Types.xtend

@@ -11,31 +11,15 @@
 package org.yakindu.sct.generator.c
 
 import com.google.inject.Inject
-import org.eclipse.xtext.generator.IFileSystemAccess
-import org.yakindu.sct.generator.core.impl.IExecutionFlowGenerator
-import org.yakindu.sct.model.sgraph.Statechart
 import org.yakindu.sct.model.sexec.ExecutionFlow
 import org.yakindu.sct.model.sgen.GeneratorEntry
-import org.yakindu.sct.generator.core.library.IOutletFeatureHelper
 
-class Types {
+class Types implements IContentTemplate {
 
 	@Inject extension Naming
 	@Inject extension GenmodelEntries
-	@Inject IOutletFeatureHelper outletFeatureHelper
 
-	def generateTypesH(ExecutionFlow flow, Statechart sc, IFileSystemAccess fsa, GeneratorEntry entry) {
-		if (outletFeatureHelper.getLibraryTargetFolderValue(entry) != null) {
-			// sc_types.h is static, so we use the library target folder in case its configured
-			fsa.generateFile(flow.typesModule.h, IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT,
-				flow.typesHContent(entry))
-		} else {
-			// use default target folder path in case no library target folder is specified (the file will be overwritten there)
-				fsa.generateFile(flow.typesModule.h, flow.typesHContent(entry))
-		}
-	}
-
-	def typesHContent(ExecutionFlow it, GeneratorEntry entry) '''
+	override content(ExecutionFlow it, GeneratorEntry entry, IGenArtifactConfigurations locations) '''
 		«entry.licenseText»
 		
 		#ifndef «typesModule.define»_H_

+ 3 - 0
plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/filesystem/EFSResourceFileSystemAccess.java

@@ -202,6 +202,9 @@ public class EFSResourceFileSystemAccess extends AbstractFileSystemAccess2 imple
 	public URI getURI(String path, String outputConfiguration) {
 		OutputConfiguration outputConfig = getOutputConfig(outputConfiguration);
 		String outputDir = outputConfig.getOutputDirectory();
+		if (efsHelper.isRootPath(outputDir) && efsHelper.isRootPath(path)) {
+			return URI.createFileURI(getProject().getLocationURI().getPath());
+		}
 		IFile file = getProject().getFile(outputDir + File.separator + path);
 		if (file != null) {
 			return URI.createFileURI(file.getLocationURI().getPath());

+ 5 - 1
plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/util/EFSHelper.java

@@ -88,11 +88,15 @@ public class EFSHelper {
 	 */
 	public IContainer getContainer(OutputConfiguration outputConfig,IProject project) {
 		String path = outputConfig.getOutputDirectory();
-		if (".".equals(path) ||"/".equals(path) || "./".equals(path) || "".equals(path) || project == null) {
+		if (isRootPath(path) || project == null) {
 			return project;
 		}
 		return project.getFolder(new Path(path));
 	}
+	
+	public boolean isRootPath(String path) {
+		return (".".equals(path) ||"/".equals(path) || "./".equals(path) || "".equals(path));
+	}
 
 	public void createContainer(IContainer container) {
 		try {

+ 2 - 2
plugins/org.yakindu.sct.generator.cpp/src/org/yakindu/sct/generator/cpp/StatemachineHeader.xtend

@@ -40,12 +40,12 @@ class StatemachineHeader extends org.yakindu.sct.generator.c.StatemachineHeader
 
 	protected GeneratorEntry entry
 
-	override generateStatemachineHeader(ExecutionFlow flow, Statechart sc, IFileSystemAccess fsa, GeneratorEntry entry) {
+	def generateStatemachineHeader(ExecutionFlow flow, Statechart sc, IFileSystemAccess fsa, GeneratorEntry entry) {
 		this.entry = entry
 		fsa.generateFile(flow.module().h, flow.generateStatemachineHeaderContents(entry))
 	}
 
-	override generateStatemachineHeaderContents(ExecutionFlow it, GeneratorEntry entry) '''
+	def generateStatemachineHeaderContents(ExecutionFlow it, GeneratorEntry entry) '''
 		«entry.licenseText»
 		
 		#ifndef «module().define»_H_