Bug 566509 - [Robotics, ROS2] Non generated files should be removed

- Remove generated files, using the cleanup functionality of the underlying
  file-system access

Change-Id: Ibbbf7be076b93e3e2118f175a0ad9d2627a47bc8
Signed-off-by: Ansgar Radermacher <ansgar.radermacher@cea.fr>
diff --git a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/RosTransformations.xtend b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/RosTransformations.xtend
index 5dfce00..b137029 100644
--- a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/RosTransformations.xtend
+++ b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/RosTransformations.xtend
@@ -36,6 +36,12 @@
 import static extension org.eclipse.papyrus.robotics.ros2.codegen.component.ComponentTransformations.*
 import static extension org.eclipse.papyrus.robotics.ros2.codegen.launch.LaunchScript.generateLaunch
 import static extension org.eclipse.papyrus.robotics.ros2.codegen.utils.PackageTools.*
+import org.eclipse.papyrus.robotics.profile.robotics.services.ServiceDefinitionModel
+import org.eclipse.core.runtime.NullProgressMonitor
+import org.eclipse.papyrus.infra.tools.file.ProjectBasedFileAccess
+import org.eclipse.papyrus.designer.languages.common.base.file.ProjectBasedFileAccessTmp
+import org.eclipse.papyrus.designer.languages.common.base.file.ICleanUntouchedTmp
+import org.eclipse.papyrus.robotics.ros2.codegen.component.ComponentTransformations
 
 class RosTransformations implements IM2MTrafoCDP {
 
@@ -61,24 +67,41 @@
 				// since the latter remove ports
 				fileAccess.generateLaunch(system)
 			}
+			val ct = new ComponentTransformations(fileAccess, project);
 			for (compDef : compDefs) {
-				compDef.componentTrafo(msgPkgCreator, project)
+				ct.componentTrafo(compDef, msgPkgCreator)
 			}
 			for (compDef : compDefs) {
-				compDef.componentCodegen(msgPkgCreator, project)
+				ct.componentCodegen(compDef, msgPkgCreator)
 			}
+			val cleanup = fileAccess as ICleanUntouchedTmp
+			cleanup.cleanUntouched(project.getFolder("src-gen"), new NullProgressMonitor);
+			cleanup.cleanUntouched(project.getFolder("src-skel"), new NullProgressMonitor);
+
 			TransformationContext.current.project = project;
 		} else {
 			throw new TransformationException(RosTransformations.USER_CANCEL);
 		}
 	}
 
+	/**
+	 * Apply transformation, support three cases
+	 * 1. User called transformation in a component definition model
+	 * 	=> apply transformation in that model (only)
+	 * 2. User called transformation in a component definition model
+	 * 	=> apply transformation in that model (only)
+	 * 3. User called transformation in a system architecture
+	 *  => obtain all components within the system
+	 */
 	override applyTrafo(M2MTrafo trafo, Package rootPkg) throws TransformationException {
 		// assure that Common and C++ profiles is applied
 		ApplyProfiles.applyCommonProfile(rootPkg)
 		ApplyProfiles.applyCppProfile(rootPkg)
 		msgPkgCreator = new CreateMsgPackage();
-		if (StereotypeUtil.isApplied(rootPkg, ComponentDefinitionModel)) {
+		if (StereotypeUtil.isApplied(rootPkg, ServiceDefinitionModel)) {
+			msgPkgCreator.createMsgPkg(rootPkg)
+		}
+		else if (StereotypeUtil.isApplied(rootPkg, ComponentDefinitionModel)) {
 			val component = rootPkg.componentFromPkg
 			if (component !== null) {
 				val pkg = PackageUtil.getRootPackage(component);
diff --git a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/Callbacks.xtend b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/Callbacks.xtend
index 4a45fb1..f34f4c6 100644
--- a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/Callbacks.xtend
+++ b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/Callbacks.xtend
@@ -48,6 +48,8 @@
 	final static String QUERY = "QUERY"
 	final static String ACTION = "ACTION"
 
+	final static String WHOLE_PKG = "Please note that code gets generated for the whole ROS2 package, not only for the currently open component"
+	
 	/**
 	 * Return the of callback method (which corresponds to activity handling the port)
 	 * and provide additional parameter
@@ -226,8 +228,9 @@
 	def static void checkActivity(ActivityPort activityPort, String portKind, Port port) {
 		if (activityPort === null) {
 			throw new TransformationException(
-				String.format("No activity is associated with port \"%s\" (requiring a handler for %s)", portKind,
-					port.name))
+				String.format("The %s port \"%s\" of component \"%s\" is not connected with any activity port. " + WHOLE_PKG,
+					portKind, port.name, port.class_.name
+				))
 		}
 	}
 
@@ -237,8 +240,8 @@
 	def static void checkFunction(Behavior function, String portKind, ActivityPort activity, Port port) {
 		if (function === null) {
 			throw new TransformationException(
-				String.format("No handler function (for %s) is found for activity port \"%s\" associated with port \"%s\"",
-					portKind, activity.base_Port.name, port.name));
+				String.format("No handler function (for %s) is found for activity port \"%s\" associated with port \"%s\" of component \"%s\". " + WHOLE_PKG,
+					portKind, activity.base_Port.name, port.name, port.class_.name));
 		}
 	}
 
diff --git a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/ComponentTransformations.xtend b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/ComponentTransformations.xtend
index f899e48..9a51fd9 100644
--- a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/ComponentTransformations.xtend
+++ b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/ComponentTransformations.xtend
@@ -45,12 +45,20 @@
 import static extension org.eclipse.papyrus.robotics.ros2.codegen.utils.MessageUtils.*
 import static extension org.eclipse.papyrus.robotics.core.utils.ParameterUtils.getAllParameters
 import static extension org.eclipse.papyrus.robotics.ros2.codegen.utils.ComponentUtils.isRegistered;
-import org.eclipse.papyrus.robotics.profile.robotics.components.ActivityPort
 import org.eclipse.emf.ecore.util.EcoreUtil
 import org.eclipse.papyrus.robotics.ros2.codegen.message.CreateMsgPackage
+import org.eclipse.papyrus.infra.tools.file.IPFileSystemAccess
 
 class ComponentTransformations {
 
+	IPFileSystemAccess fileAccess;
+	IProject genProject
+ 
+ 	new(IPFileSystemAccess fileAccess, IProject genProject) {
+ 		this.fileAccess = fileAccess;
+ 		this.genProject = genProject;
+ 	}
+ 	
 	/**
 	 * Move functions in passed activity to component (node) level
 	 */
@@ -217,7 +225,7 @@
 		}	
 	}
 	
-	def static componentTrafo(Class component, CreateMsgPackage msgPkgCreator, IProject genProject) {
+	def componentTrafo(Class component, CreateMsgPackage msgPkgCreator) {
 		msgPkgCreator.createMessagesOrServices(component)
 	
 		if (genProject === null) {
@@ -259,10 +267,12 @@
 
 	}
 
-	def static componentCodegen(Class component, CreateMsgPackage msgPkgCreator, IProject genProject) {
+	def componentCodegen(Class component, CreateMsgPackage msgPkgCreator) {
+		val codeGen = new RoboticsCppCreator(fileAccess, "src-skel/")
+		
 		component.removeTemplateSig
 		component.removePorts
-		TransformationContext.current.project = genProject;
-		ProjectTools.genCode(genProject, component);
+		TransformationContext.current.project = genProject
+		ProjectTools.genCode(codeGen, component)
 	}
 }
diff --git a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/RoboticsCppCreator.java b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/RoboticsCppCreator.java
index d15b805..c0e25f0 100644
--- a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/RoboticsCppCreator.java
+++ b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/component/RoboticsCppCreator.java
@@ -14,8 +14,8 @@
 
 package org.eclipse.papyrus.robotics.ros2.codegen.component;
 
-import org.eclipse.core.resources.IProject;
 import org.eclipse.papyrus.designer.languages.cpp.codegen.transformation.CppModelElementsCreator;
+import org.eclipse.papyrus.infra.tools.file.IPFileSystemAccess;
 import org.eclipse.uml2.uml.NamedElement;
 
 /**
@@ -27,27 +27,24 @@
 
 	String skeletonFolder;
 
-	NamedElement skeleton;
-
 	/**
 	 * Constructor.
 	 *
-	 * @param project the project
-	 * @param skeletonFolder the folder, into which skeletons should be placed (with a trailing "/")
-	 * @param skeleton the skeleton
+	 * @param fileAccess
+	 *            the file system access
+	 * @param skeletonFolder
+	 *            the folder, into which skeletons should be placed (with a trailing "/")
 	 */
-	public RoboticsCppCreator(IProject project, String skeletonFolder, NamedElement skeleton) {
-		super(project);
+	public RoboticsCppCreator(IPFileSystemAccess fileAccess, String skeletonFolder) {
+		super(fileAccess, null);
 		this.skeletonFolder = skeletonFolder;
-		this.skeleton = skeleton;
 	}
 
 	@Override
 	public String getFileName(NamedElement element) {
-		if (element == skeleton) {
+		if (element.getName() != null && element.getName().endsWith(CodeSkeleton.POSTFIX)) {
 			return skeletonFolder + locStrategy.getFileName(element);
-		}
-		else {
+		} else {
 			return super.getFileName(element);
 		}
 	}
diff --git a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/handlers/GenerateCodeHandler.java b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/handlers/GenerateCodeHandler.java
index 13137de..342ea00 100644
--- a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/handlers/GenerateCodeHandler.java
+++ b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/handlers/GenerateCodeHandler.java
@@ -30,7 +30,7 @@
 import org.eclipse.papyrus.uml.diagram.common.handlers.CmdHandler;
 import org.eclipse.papyrus.uml.tools.utils.PackageUtil;
 import org.eclipse.ui.progress.UIJob;
-import org.eclipse.uml2.uml.Class;
+import org.eclipse.uml2.uml.Classifier;
 import org.eclipse.uml2.uml.Package;
 
 @SuppressWarnings("nls")
@@ -41,11 +41,11 @@
 	@Override
 	public Object execute(ExecutionEvent arg0) throws ExecutionException {
 		updateSelectedEObject();
-		if (!(selectedEObject instanceof Class)) {
+		if (!(selectedEObject instanceof Classifier)) {
 			return null;
 		}
 
-		Package pkg = PackageUtil.getRootPackage((Class) selectedEObject);
+		Package pkg = PackageUtil.getRootPackage((Classifier) selectedEObject);
 		PrepareCodegenCmd prepareCmd = new PrepareCodegenCmd(pkg);
 		if (prepareCmd.prepare()) {
 			IProject project = ProjectManagement.getCurrentProject();
diff --git a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/message/CreateMessage.xtend b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/message/CreateMessage.xtend
index 83aa795..46419e5 100644
--- a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/message/CreateMessage.xtend
+++ b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/message/CreateMessage.xtend
@@ -27,6 +27,7 @@
 import static extension org.eclipse.papyrus.robotics.core.utils.InteractionUtils.*
 import static extension org.eclipse.papyrus.robotics.ros2.codegen.utils.MessageUtils.*
 import static extension org.eclipse.papyrus.robotics.ros2.codegen.utils.PackageTools.pkgName
+import org.eclipse.papyrus.robotics.ros2.codegen.utils.MessageUtils
 
 class CreateMessage {
 
@@ -134,24 +135,6 @@
 	 * The user can specify a configurable path that containing entries that should not be
 	 * re-written by code generation.
 	 */
-	def void generateMsgFile(IPFileSystemAccess fileAccess, String fileName, CharSequence content) {
-		// check, if message requires creation
-		generateFile(fileAccess, fileName, "msg", content)
-	}
-
-	def void generateSrvFile(IPFileSystemAccess fileAccess, String fileName, CharSequence content) {
-		// check, if service requires creation
-		generateFile(fileAccess, fileName, "srv", content)
-	}
-
-	def void generateActFile(IPFileSystemAccess fileAccess, String fileName, CharSequence content) {
-		// check, if service requires creation
-		generateFile(fileAccess, fileName, "action", content)
-	}
-
-	/**
-	 * @param fileName = fileName without extension
-	 */
 	def void generateFile(IPFileSystemAccess fileAccess, String fileName, String ext, CharSequence content) {
 		val fileNameWithExt = '''«ext»/«fileName».«ext»'''
 
diff --git a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/message/CreateMsgPackage.xtend b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/message/CreateMsgPackage.xtend
index a74e075..8ef8a1d 100644
--- a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/message/CreateMsgPackage.xtend
+++ b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/message/CreateMsgPackage.xtend
@@ -33,6 +33,8 @@
 import static extension org.eclipse.papyrus.robotics.core.utils.InteractionUtils.*
 import static extension org.eclipse.papyrus.robotics.ros2.codegen.utils.MessageUtils.*
 import static extension org.eclipse.papyrus.robotics.ros2.codegen.utils.PackageTools.pkgName
+import org.eclipse.core.runtime.CoreException
+import org.eclipse.core.runtime.NullProgressMonitor
 
 /**
  * Handle creation of a ROS2 message package
@@ -120,14 +122,14 @@
 
 		// messages covers push and send
 		for (msg : srcPkg.messages) {
-			cm.generateMsgFile(fileAccess, msg.name, cm.createDatatypeMsg(msg))
+			cm.generateFile(fileAccess, msg.name, MessageUtils.MESSAGE, cm.createDatatypeMsg(msg))
 		}
 		for (sd : srcPkg.queries) {
 			// request and reply data types are found in communication package
 			val tb = sd.templateBinding
 			val req = MessageUtils.getRequest(tb)
 			val res = MessageUtils.getResponse(tb)
-			cm.generateSrvFile(fileAccess, sd.nameWoPrefix, cm.createServiceMsg(req as DataType, res as DataType))
+			cm.generateFile(fileAccess, sd.nameWoPrefix, MessageUtils.SERVICE, cm.createServiceMsg(req as DataType, res as DataType))
 		}
 		for (sd : srcPkg.actions) {
 			// request and reply data types are found in communication package
@@ -135,7 +137,14 @@
 			val goal = MessageUtils.getGoal(tb)
 			val res = MessageUtils.getResponse(tb)
 			val feedback = MessageUtils.getFeedback(tb)
-			cm.generateActFile(fileAccess, sd.nameWoPrefix, cm.createActionMsg(goal as DataType, res as DataType, feedback as DataType))
+			cm.generateFile(fileAccess, sd.nameWoPrefix, MessageUtils.SERVICE, cm.createActionMsg(goal as DataType, res as DataType, feedback as DataType))
+		}
+		try {
+			fileAccess.cleanUntouched(project.getFolder(MessageUtils.MESSAGE), new NullProgressMonitor);
+			fileAccess.cleanUntouched(project.getFolder(MessageUtils.SERVICE), new NullProgressMonitor);
+			fileAccess.cleanUntouched(project.getFolder(MessageUtils.ACTION), new NullProgressMonitor);
+		} catch (CoreException e) {
+			throw new RuntimeException(e);
 		}
 	}
 
diff --git a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/utils/MessageUtils.xtend b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/utils/MessageUtils.xtend
index ab0f80b..699bc7e 100644
--- a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/utils/MessageUtils.xtend
+++ b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/utils/MessageUtils.xtend
@@ -53,11 +53,11 @@
 
 class MessageUtils {
 
-	package val static MESSAGE = "msg"
+	public val static MESSAGE = "msg"
 
-	package val static SERVICE = "srv"
+	public val static SERVICE = "srv"
 
-	package val static ACTION = "action"
+	public val static ACTION = "action"
 
 	/** 
 	 * Return the message package, i.e. the first package (navigating up) that applies the
diff --git a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/utils/ProjectTools.xtend b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/utils/ProjectTools.xtend
index c9a5b32..e88f8c5 100644
--- a/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/utils/ProjectTools.xtend
+++ b/plugins/ros2/org.eclipse.papyrus.robotics.ros2.codegen/src/org/eclipse/papyrus/robotics/ros2/codegen/utils/ProjectTools.xtend
@@ -184,9 +184,7 @@
 	/**
 	 * 
 	 */
-	static def genCode(IProject project, Class component) {
-		val skeleton = component.nearestPackage.getMember(component.name + CodeSkeleton.POSTFIX)
-		val codeGen = new RoboticsCppCreator(project, "src-skel/", skeleton);
+	static def genCode(RoboticsCppCreator codeGen, Class component) {
 		val packagesToGenerate = new UniqueEList<Package>();
 		packagesToGenerate.add(component.nearestPackage);
 		for (incCl : CppClassUtils.includedClassifiers(component)) {