Browse Source

#845: Added apiTargetFolder to outlet feature. Adjusted C, C++ and Java code generator to make use of API target folder if it is set.

Thomas Kutz 9 years ago
parent
commit
d69c7c1716
16 changed files with 141 additions and 41 deletions
  1. 3 0
      plugins/org.yakindu.sct.doc.user/src/user-guide/generating_code.textile
  2. 1 1
      plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/CCodeGenerator.java
  3. 25 10
      plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/CGenerator.xtend
  4. 4 0
      plugins/org.yakindu.sct.generator.core/library/CoreFeatureTypeLibrary.xmi
  5. 5 0
      plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/AbstractWorkspaceGenerator.java
  6. 1 0
      plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/features/ICoreFeatureConstants.java
  7. 3 1
      plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/features/impl/CoreLibraryDefaultFeatureValueProvider.java
  8. 14 0
      plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/impl/AbstractSGraphModelGenerator.java
  9. 1 0
      plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/impl/IExecutionFlowGenerator.java
  10. 13 1
      plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/library/IOutletFeatureHelper.java
  11. 14 3
      plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/library/OutletFeatureHelperImpl.java
  12. 27 18
      plugins/org.yakindu.sct.generator.cpp/src/org/yakindu/sct/generator/cpp/CppGenerator.xtend
  13. 8 3
      plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/IStatemachine.xtend
  14. 7 2
      plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/ITimer.xtend
  15. 5 1
      plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/ITimerCallback.xtend
  16. 10 1
      plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/StatemachineInterface.xtend

+ 3 - 0
plugins/org.yakindu.sct.doc.user/src/user-guide/generating_code.textile

@@ -60,6 +60,8 @@ The *Outlet* feature specifies target project and target folder for the generate
 # _targetProject_ (String, required): The project to store the generated artifacts to.
 # _targetFolder_ (String, required): The folder to store the generated artifacts to. If a library folder is given, only the dynamic (i. e. model-dependent artifacts) are generated into the target folder, if not all generated artifacts will be generated into it. All artifacts in this folder will be overwritten during re-generation.
 # _libraryTargetFolder_ (String, optional): The folder to store the static (i. e. model-independent artifacts) to. In case this is not specified, all artifacts will be generated into the target folder. All artifacts in this folder will be preserved during re-generation.
+# _apiTargetFolder_ (String, optional): The folder to store API code, e.g. interfaces or header files. In case this is not specified, all artifacts will be generated into the target folder.
+
 
 bq.. *Example:*
 
@@ -67,6 +69,7 @@ bc. feature Outlet {
     targetProject = "SampleProject"
     targetFolder = "src-gen"
     libraryTargetFolder = "src"
+    apiTargetFolder = "api-gen"
 }
 
 ==<!-- End sgen_feature_outlet -->==

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

@@ -52,7 +52,7 @@ public class CCodeGenerator extends GenericJavaBasedGenerator {
 		super.prepareGenerator(entry);
 		initGenArtifactConfigurations();
 	}
-
+	
 	protected void initGenArtifactConfigurations() {
 		artifactConfigs.setFileSystemAccess(sctFsa);
 	}

+ 25 - 10
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/CGenerator.xtend

@@ -25,7 +25,7 @@ import org.yakindu.sct.generator.c.GenArtifactConfigurations.GenArtifactConfigur
  * @author Axel Terfloth
  */
 class CGenerator implements IExecutionFlowGenerator {
-	 
+	
 	@Inject extension Types types
 	@Inject extension StatemachineHeader statemachineHeader
 	@Inject extension StatemachineSource statemachineSource
@@ -33,8 +33,7 @@ class CGenerator implements IExecutionFlowGenerator {
 	@Inject extension Navigation
 	@Inject extension GenmodelEntries
 	@Inject extension Naming
-	
-	@Inject IOutletFeatureHelper outletFeatureHelper
+	@Inject extension IOutletFeatureHelper
 
 	@Inject @Named(IGenArtifactConfigurations.DEFAULT)
 	IGenArtifactConfigurations defaultConfigs
@@ -59,16 +58,32 @@ class CGenerator implements IExecutionFlowGenerator {
 	}
 	
 	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)
+		locations.configure(flow.typesModule.h, entry.libraryOutput, types)
+		locations.configure(flow.module.h, entry.headerOutput, statemachineHeader)
+		locations.configure(flow.module.c, entry.sourceOutput, statemachineSource)
+		if (flow.timed || !flow.operations.empty || entry.tracingEnterState || entry.tracingExitState) {
+			locations.configure(flow.module.client.h, entry.headerOutput, statemachineRequiredHeader)
+		}
+	}
+	
+	def protected getHeaderOutput(GeneratorEntry entry) {
+		if (entry.apiTargetFolderValue != null) {
+			IExecutionFlowGenerator.API_TARGET_FOLDER_OUTPUT
 		} else {
-			locations.configure(flow.typesModule.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, types)
+			IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT
 		}
-		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.configure(flow.module.client.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, statemachineRequiredHeader)
+	}
+
+	def protected getLibraryOutput(GeneratorEntry entry) {
+		if (entry.libraryTargetFolderValue != null) {
+			IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT
+		} else {
+			entry.headerOutput
 		}
 	}
 	
+	def protected getSourceOutput(GeneratorEntry entry) {
+		IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT
+	}
+	
 }

+ 4 - 0
plugins/org.yakindu.sct.generator.core/library/CoreFeatureTypeLibrary.xmi

@@ -13,6 +13,10 @@
         name="libraryTargetFolder"
         comment="A distinct output folder for static code artifacts (which are independent of concrete statechart models). It will not be cleaned or overwritten in succeeding generation passes. If not specified, the code will be generated into the target folder as well."
         optional="true"/>
+    <parameters
+        name="apiTargetFolder"
+        comment="A distinct output folder for API code artifacts. If not specified, the code will be generated into the target folder."
+        optional="true"/>
   </types>
   <types name="LicenseHeader"
       optional="true">

+ 5 - 0
plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/AbstractWorkspaceGenerator.java

@@ -51,6 +51,11 @@ public abstract class AbstractWorkspaceGenerator extends AbstractSExecModelGener
 		return new File(uri.toFileString());
 	}
 	
+	public final File getApiTargetFolder(GeneratorEntry entry) {
+		URI uri = sctFsa.getURI(outletFeatureHelper.getRelativeApiFolder(entry));
+		return new File(uri.toFileString());
+	}
+	
 	public final void writeToConsole(String line){
 		log.writeToConsole(line);
 	}

+ 1 - 0
plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/features/ICoreFeatureConstants.java

@@ -25,6 +25,7 @@ public interface ICoreFeatureConstants {
 	public static final String OUTLET_FEATURE_TARGET_PROJECT = "targetProject";
 	public static final String OUTLET_FEATURE_TARGET_FOLDER = "targetFolder";
 	public static final String OUTLET_FEATURE_LIBRARY_TARGET_FOLDER = "libraryTargetFolder";
+	public static final String OUTLET_FEATURE_API_TARGET_FOLDER = "apiTargetFolder";
 	
 	public static final String LICENSE_HEADER = "LicenseHeader";
 	public static final String LICENSE_TEXT = "licenseText";

+ 3 - 1
plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/features/impl/CoreLibraryDefaultFeatureValueProvider.java

@@ -15,6 +15,7 @@ import static org.yakindu.sct.generator.core.features.ICoreFeatureConstants.LICE
 import static org.yakindu.sct.generator.core.features.ICoreFeatureConstants.OUTLET_FEATURE_TARGET_FOLDER;
 import static org.yakindu.sct.generator.core.features.ICoreFeatureConstants.OUTLET_FEATURE_TARGET_PROJECT;
 import static org.yakindu.sct.generator.core.features.ICoreFeatureConstants.OUTLET_FEATURE_LIBRARY_TARGET_FOLDER;
+import static org.yakindu.sct.generator.core.features.ICoreFeatureConstants.OUTLET_FEATURE_API_TARGET_FOLDER;
 
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
@@ -58,7 +59,8 @@ public class CoreLibraryDefaultFeatureValueProvider extends AbstractDefaultFeatu
 				&& !projectOpened(parameterValue.getStringValue()))
 			return error(String.format("The Project %s is not open.", parameterValue.getExpression()));
 		if (OUTLET_FEATURE_TARGET_FOLDER.equals(parameterName)
-				|| OUTLET_FEATURE_LIBRARY_TARGET_FOLDER.equals(parameterName)) {
+				|| OUTLET_FEATURE_LIBRARY_TARGET_FOLDER.equals(parameterName)
+				|| OUTLET_FEATURE_API_TARGET_FOLDER.equals(parameterName)) {
 			FeatureParameterValue targetProjectParam = parameterValue.getFeatureConfiguration()
 					.getParameterValue(OUTLET_FEATURE_TARGET_PROJECT);
 			String targetProjectName = targetProjectParam != null ? targetProjectParam.getStringValue() : null;

+ 14 - 0
plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/impl/AbstractSGraphModelGenerator.java

@@ -188,6 +188,7 @@ public abstract class AbstractSGraphModelGenerator implements ISCTGenerator {
 		initFsaTargetProject(entry);
 		initDefaultOutput(entry);
 		initLibraryTargetFolder(entry);
+		initApiTargetFolder(entry);
 	}
 
 	protected void initLibraryTargetFolder(GeneratorEntry entry) {
@@ -207,6 +208,19 @@ public abstract class AbstractSGraphModelGenerator implements ISCTGenerator {
 			librarytargetFolderOutputConfiguration.setOverrideExistingResources(false);
 		}
 	}
+	
+	protected void initApiTargetFolder(GeneratorEntry entry) {
+		FeatureParameterValue apiTargetFolderValue = outletFeatureHelper.getApiTargetFolderValue(entry);
+		if (apiTargetFolderValue != null) {
+			sctFsa.setOutputPath(IExecutionFlowGenerator.API_TARGET_FOLDER_OUTPUT,
+					apiTargetFolderValue.getStringValue());
+		}
+		OutputConfiguration apiTargetFolderOutputConfiguration = sctFsa.getOutputConfigurations()
+				.get(IExecutionFlowGenerator.API_TARGET_FOLDER_OUTPUT);
+		if (apiTargetFolderOutputConfiguration != null) {
+			apiTargetFolderOutputConfiguration.setCreateOutputDirectory(true);
+		}
+	}
 
 	protected void initDefaultOutput(GeneratorEntry entry) {
 		sctFsa.setOutputPath(IFileSystemAccess.DEFAULT_OUTPUT,

+ 1 - 0
plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/impl/IExecutionFlowGenerator.java

@@ -18,6 +18,7 @@ public interface IExecutionFlowGenerator {
 
 	String TARGET_FOLDER_OUTPUT = IFileSystemAccess.DEFAULT_OUTPUT;
 	String LIBRARY_TARGET_FOLDER_OUTPUT = "LIBRARY_TARGET_FOLDER";
+	String API_TARGET_FOLDER_OUTPUT = "API_TARGET_FOLDER";
 
 	/**
 	 * 

+ 13 - 1
plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/library/IOutletFeatureHelper.java

@@ -31,11 +31,17 @@ public interface IOutletFeatureHelper {
 	 */
 	FeatureParameterValue getTargetFolderValue(GeneratorEntry entry);
 	/**
-	 * The libraryFolder value defined in SGen.
+	 * The libraryTargetFolder value defined in SGen.
 	 * @param entry
 	 * @return the library target folder value
 	 */
 	FeatureParameterValue getLibraryTargetFolderValue(GeneratorEntry entry);
+	/**
+	 * The apiTargetFolder value defined in SGen.
+	 * @param entry
+	 * @return the api target folder value
+	 */
+	FeatureParameterValue getApiTargetFolderValue(GeneratorEntry entry);
 	/**
 	 * The project value defined in SGen.
 	 * @param entry
@@ -54,4 +60,10 @@ public interface IOutletFeatureHelper {
 	 * @return a string representing the relative output path 'targetProject/libraryTargetFolder'
 	 */
 	String getRelativeLibraryFolder(GeneratorEntry entry);
+	/**
+	 * Convenience to combine targetProject & apiTargetFolder values defined in SGen.
+	 * @param entry
+	 * @return a string representing the relative output path 'targetProject/apiTargetFolder'
+	 */
+	String getRelativeApiFolder(GeneratorEntry entry);
 }

+ 14 - 3
plugins/org.yakindu.sct.generator.core/src/org/yakindu/sct/generator/core/library/OutletFeatureHelperImpl.java

@@ -31,6 +31,11 @@ public class OutletFeatureHelperImpl extends BaseSGenFeatureHelper implements IO
 	public FeatureParameterValue getLibraryTargetFolderValue(GeneratorEntry entry) {
 		return getFeatureParameter(entry, OUTLET_FEATURE, ICoreFeatureConstants.OUTLET_FEATURE_LIBRARY_TARGET_FOLDER);
 	}
+	
+	@Override
+	public FeatureParameterValue getApiTargetFolderValue(GeneratorEntry entry) {
+		return getFeatureParameter(entry, OUTLET_FEATURE, ICoreFeatureConstants.OUTLET_FEATURE_API_TARGET_FOLDER);
+	}
 
 	@Override
 	public FeatureParameterValue getTargetProjectValue(GeneratorEntry entry) {
@@ -47,8 +52,14 @@ public class OutletFeatureHelperImpl extends BaseSGenFeatureHelper implements IO
 	@Override
 	public String getRelativeLibraryFolder(GeneratorEntry entry) {
 		String projectFolderName = getTargetProjectValue(entry).getStringValue();
-		String libraryFolderName = getLibraryTargetFolderValue(entry).getExpression().toString();
-		return projectFolderName + Path.SEPARATOR
-				+ libraryFolderName;
+		String libraryFolderName = getLibraryTargetFolderValue(entry).getStringValue();
+		return projectFolderName + Path.SEPARATOR + libraryFolderName;
+	}
+	
+	@Override
+	public String getRelativeApiFolder(GeneratorEntry entry) {
+		String projectFolderName = getTargetProjectValue(entry).getStringValue();
+		String apiFolderName = getApiTargetFolderValue(entry).getStringValue();
+		return projectFolderName + Path.SEPARATOR + apiFolderName;
 	}
 }

+ 27 - 18
plugins/org.yakindu.sct.generator.cpp/src/org/yakindu/sct/generator/cpp/CppGenerator.xtend

@@ -35,8 +35,7 @@ class CppGenerator implements IExecutionFlowGenerator {
 	@Inject extension StatemachineImplementation statemachineSourceContent
 	@Inject extension Navigation
 	@Inject extension Naming
-	
-	@Inject IOutletFeatureHelper outletFeatureHelper
+	@Inject extension IOutletFeatureHelper
 	
 	@Inject @Named(IGenArtifactConfigurations.DEFAULT)
 	IGenArtifactConfigurations defaultConfigs
@@ -61,26 +60,36 @@ class CppGenerator implements IExecutionFlowGenerator {
 	}
 	
 	def initGenerationArtifacts(ExecutionFlow flow, GeneratorEntry entry, IGenArtifactConfigurations locations) {
-		if (outletFeatureHelper.getLibraryTargetFolderValue(entry) != null) {
-			locations.configure(flow.typesModule.h, IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT, typesContent)
-		} else {
-			locations.configure(flow.typesModule.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, typesContent)
-		}
-		
-		locations.configure(statemachineInterface.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, statemachineInterfaceContent)
+		locations.configure(flow.typesModule.h, entry.libraryOutput, typesContent)
+		locations.configure(statemachineInterface.h, entry.headerOutput, statemachineInterfaceContent)
 		
 		if (flow.timed) {
-			if (outletFeatureHelper.getLibraryTargetFolderValue(entry) != null) {
-				locations.configure(timedStatemachineInterface.h, IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT, timedStatemachineInterfaceContent)
-				locations.configure(timerInterface.h, IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT, timerInterfaceContent)
-			} else {
-				locations.configure(timedStatemachineInterface.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, timedStatemachineInterfaceContent)
-				locations.configure(timerInterface.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, timerInterfaceContent)
-			}
+				locations.configure(timedStatemachineInterface.h, entry.libraryOutput, timedStatemachineInterfaceContent)
+				locations.configure(timerInterface.h, entry.libraryOutput, timerInterfaceContent)
 		}
 		
-		locations.configure(flow.module.h, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, statemachineHeaderContent)
-		locations.configure(flow.module.cpp, IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT, statemachineSourceContent)
+		locations.configure(flow.module.h, entry.headerOutput, statemachineHeaderContent)
+		locations.configure(flow.module.cpp, entry.sourceOutput, statemachineSourceContent)
+	}
+	
+	def protected getHeaderOutput(GeneratorEntry entry) {
+		if (entry.apiTargetFolderValue != null) {
+			IExecutionFlowGenerator.API_TARGET_FOLDER_OUTPUT
+		} else {
+			IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT
+		}
+	}
+
+	def protected getLibraryOutput(GeneratorEntry entry) {
+		if (entry.libraryTargetFolderValue != null) {
+			IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT
+		} else {
+			entry.headerOutput
+		}
+	}
+	
+	def protected getSourceOutput(GeneratorEntry entry) {
+		IExecutionFlowGenerator.TARGET_FOLDER_OUTPUT
 	}
 	
 }

+ 8 - 3
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/IStatemachine.xtend

@@ -28,11 +28,16 @@ class IStatemachine {
 	@Inject IOutletFeatureHelper outletFeatureHelper
 	 
 	def generateIStatemachine(ExecutionFlow flow, GeneratorEntry entry, IFileSystemAccess fsa) {
-		if (outletFeatureHelper.getLibraryTargetFolderValue(entry) != null) {	
+		if (outletFeatureHelper.getLibraryTargetFolderValue(entry) != null) {
 			// generate into library target folder in case one is specified, as the contents are static
-			fsa.generateFile(entry.basePackagePath + '/' + iStatemachine.java, IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT, content(entry))
+			fsa.generateFile(entry.basePackagePath + '/' + iStatemachine.java,
+				IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT, content(entry))
+		} else if (outletFeatureHelper.getApiTargetFolderValue(entry) != null) {
+			// generate into API target folder in case one is specified, as it is an interface
+			fsa.generateFile(entry.basePackagePath + '/' + iStatemachine.java,
+				IExecutionFlowGenerator.API_TARGET_FOLDER_OUTPUT, content(entry))
 		} else {
-			// use default target folder path in case no library target folder is specified (the file will be overwritten there)
+			// use default target folder path in case no library or API target folder is specified (the file will be overwritten there)
 			fsa.generateFile(entry.basePackagePath + '/' + iStatemachine.java, content(entry))
 		}
 	}

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

@@ -28,9 +28,14 @@ class ITimer {
 	@Inject IOutletFeatureHelper outletFeatureHelper
 	
 	def generateITimer(ExecutionFlow flow, GeneratorEntry entry, IFileSystemAccess fsa) {
-		if (outletFeatureHelper.getLibraryTargetFolderValue(entry) != null) {	
+		if (outletFeatureHelper.getLibraryTargetFolderValue(entry) != null) {
 			// generate into library target folder in case one is specified, as the contents are static
-			fsa.generateFile(entry.basePackagePath + '/' + iTimer.java, IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT, content(entry))
+			fsa.generateFile(entry.basePackagePath + '/' + iTimer.java,
+				IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT, content(entry))
+		} else if (outletFeatureHelper.getApiTargetFolderValue(entry) != null) {
+			// generate into API target folder in case one is specified, as it is an interface
+			fsa.generateFile(entry.basePackagePath + '/' + iTimer.java,
+				IExecutionFlowGenerator.API_TARGET_FOLDER_OUTPUT, content(entry))
 		} else {
 			// use default target folder path in case no library target folder is specified (the file will be overwritten there)
 			fsa.generateFile(entry.basePackagePath + '/' + iTimer.java, content(entry))

+ 5 - 1
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/ITimerCallback.xtend

@@ -31,8 +31,12 @@ class ITimerCallback {
 			// generate into library target folder in case one is specified, as the contents are static
 			fsa.generateFile(entry.basePackagePath + '/' + iTimerCallback.java,
 				IExecutionFlowGenerator.LIBRARY_TARGET_FOLDER_OUTPUT, content(entry))
+		} else if (outletFeatureHelper.getApiTargetFolderValue(entry) != null) {
+			// generate into API target folder in case one is specified, as it is an interface
+			fsa.generateFile(entry.basePackagePath + '/' + iTimerCallback.java,
+				IExecutionFlowGenerator.API_TARGET_FOLDER_OUTPUT, content(entry))
 		} else {
-			// use default target folder path in case no library target folder is specified (the file will be overwritten there)
+			// use default target folder path in case no library or API target folder is specified (the file will be overwritten there)
 			fsa.generateFile(entry.basePackagePath + '/' + iTimerCallback.java, content(entry))
 		}
 	}

+ 10 - 1
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/StatemachineInterface.xtend

@@ -23,6 +23,8 @@ import org.yakindu.sct.model.stext.stext.InterfaceScope
 import org.yakindu.sct.model.stext.stext.InternalScope
 import org.yakindu.sct.model.stext.stext.OperationDefinition
 import org.yakindu.sct.model.stext.stext.VariableDefinition
+import org.yakindu.sct.generator.core.library.IOutletFeatureHelper
+import org.yakindu.sct.generator.core.impl.IExecutionFlowGenerator
 
 class StatemachineInterface {
 
@@ -34,11 +36,18 @@ class StatemachineInterface {
 	@Inject extension ICodegenTypeSystemAccess
 	@Inject extension ExpressionCode
 	@Inject Beautifier beautifier
+	
+	@Inject IOutletFeatureHelper outletFeatureHelper
 
 	def generateStatemachineInterface(ExecutionFlow flow, GeneratorEntry entry, IFileSystemAccess fsa) {
 		var filename = flow.getImplementationPackagePath(entry) + '/' + flow.statemachineInterfaceName.java
 		var content = beautifier.format(filename, content(flow, entry))
-		fsa.generateFile(filename, content)
+		if (outletFeatureHelper.getApiTargetFolderValue(entry) != null) {
+			// generate into API target folder in case one is specified, as it is an interface
+			fsa.generateFile(filename, IExecutionFlowGenerator.API_TARGET_FOLDER_OUTPUT, content)
+		} else {
+			fsa.generateFile(filename, content)
+		}
 	}
 
 	def protected content(ExecutionFlow flow, GeneratorEntry entry) {