diff --git a/scheduling-abstraction-layer/pom.xml b/scheduling-abstraction-layer/pom.xml
index ee70e446b2e39020f900d85c74053fb2ff406624..b00ebcc09768836cc5ecbb523cbeb61b53384710 100644
--- a/scheduling-abstraction-layer/pom.xml
+++ b/scheduling-abstraction-layer/pom.xml
@@ -79,6 +79,11 @@
5.4.22.Final
compile
+
+ org.jdom
+ jdom2
+ 2.0.6.1
+
org.mariadb.jdbc
mariadb-java-client
diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/workflow/analyser/WfAnalyser.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/workflow/analyser/WfAnalyser.java
new file mode 100644
index 0000000000000000000000000000000000000000..322ff401eec036c42d8ec5b2034a6f6592cf86c5
--- /dev/null
+++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/workflow/analyser/WfAnalyser.java
@@ -0,0 +1,116 @@
+package org.activeeon.morphemic.workflow.analyser;
+
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.JDOMException;
+import org.jdom2.input.SAXBuilder;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/*
+ * This class contains the java endpoints that build from a Camel model the component grouping JSON
+ * and the dot graph syntax of the application.
+ *
+ * Developed by Activeeon in the context of H2020 MORPHEMIC project.
+ * @author Activeeon R&D Department
+ */
+
+public class WfAnalyser {
+
+ // Environment Variable Name for the camel xmi model path = CAMEL_XMI_DIR, e.g. CAMEL_XMI_DIR = "/users/user1/Documents/camel.xmi"
+ private static final String PROPERTIES_FILE_ENVIRONMENT_VARIABLE_NAME = "CAMEL_XMI_DIR";
+
+ Element camelModelRoot;
+
+ WfAnalyserCamelUtils wfAnalyserCamelUtils;
+
+ public WfAnalyser() throws IOException, JDOMException {
+ SAXBuilder builder = new SAXBuilder();
+ String path = System.getenv(PROPERTIES_FILE_ENVIRONMENT_VARIABLE_NAME);
+ File xmiFile = new File(path);
+ Document document = builder.build(xmiFile);
+ this.camelModelRoot = document.getRootElement();
+ wfAnalyserCamelUtils = new WfAnalyserCamelUtils(this.camelModelRoot);
+ }
+
+ public WfAnalyser(String path) throws IOException, JDOMException {
+ SAXBuilder builder = new SAXBuilder();
+ File xmiFile = new File(path);
+ Document document = builder.build(xmiFile);
+ this.camelModelRoot = document.getRootElement();
+ wfAnalyserCamelUtils = new WfAnalyserCamelUtils(this.camelModelRoot);
+ }
+
+ public JSONObject getJsonGrouping() {
+ JSONObject result = new JSONObject();
+ JSONArray applicationComponents = new JSONArray();
+
+ // Get application name
+ Element applicationElement = camelModelRoot.getChild("application");
+ result.put("Application_name", applicationElement.getAttributeValue("name"));
+
+ // Get number of components
+ List components = camelModelRoot.getChild("deploymentModels").getChildren("softwareComponents");
+ result.put("Number_of_components", components.size());
+
+ // App Requirements
+ result.put("General_requirements", wfAnalyserCamelUtils.getAppRequirements(components.size()));
+
+ // Get components metadata: name, requirements, long_lived, ...
+ for(Element component: components){
+ JSONObject componentMetaData = new JSONObject();
+
+ // Get component name
+ componentMetaData.put("name", component.getAttributeValue("name"));
+
+ // Get component long_lived value if it exists
+ componentMetaData.put("Long_lived", component.getAttributeValue("longLived"));
+
+ // Get resource requirements
+ String resourceReqValue = component.getAttributeValue("requirementSet");
+ int reqIndex = Integer.parseInt(resourceReqValue.split("@requirementSets.")[1]);
+ JSONArray resourceRequirements = wfAnalyserCamelUtils.getResourceRequirements(reqIndex);
+ componentMetaData.put("Resources", resourceRequirements);
+
+ // Get component variants
+ componentMetaData.put("Variants", WfAnalyserXmiElementUtils.getVariants(component));
+
+ applicationComponents.put(componentMetaData);
+ }
+ result.put("Application_components", applicationComponents);
+ result.put("Application_graph", wfAnalyserCamelUtils.getWorkflowArchitecture());
+ return result;
+ }
+
+ public String generateDotGraph() {
+ StringBuilder dotGraphSyntax = new StringBuilder();
+
+ // Write the dot file header
+ dotGraphSyntax.append("digraph g {\n");
+
+ // Add components to the do graph
+ List components = camelModelRoot.getChild("deploymentModels").getChildren("softwareComponents");
+ for(Element component: components) {
+ dotGraphSyntax.append(component.getAttributeValue("name")).append("[fontcolor=black, color=orange];\n");
+ }
+ // Add required communication
+ for(Element component: components) {
+ List requiredCommunications = component.getChildren("requiredCommunications");
+ for(Element requiredCommunication: requiredCommunications) {
+ dotGraphSyntax.append(WfAnalyserXmiElementUtils.findRequiredComponent(components, requiredCommunication.getAttributeValue("portNumber")))
+ .append("->")
+ .append(component.getAttributeValue("name"))
+ .append(" [fillcolor=grey, fontcolor=blue, color=grey, fontsize=6]").append(";");
+ dotGraphSyntax.append("\n");
+ }
+ }
+ // Write the dot file end character
+ dotGraphSyntax.append("}\n");
+ return dotGraphSyntax.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/workflow/analyser/WfAnalyserCamelUtils.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/workflow/analyser/WfAnalyserCamelUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd81ca847bfe1ad1d3dc3529d29ceef4e9c62589
--- /dev/null
+++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/workflow/analyser/WfAnalyserCamelUtils.java
@@ -0,0 +1,137 @@
+package org.activeeon.morphemic.workflow.analyser;
+
+import lombok.AllArgsConstructor;
+import org.jdom2.Element;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.List;
+
+/*
+ * This class contains the methods that handle an XMI model to generate the corresponding JSON objects.
+ *
+ * Developed by Activeeon in the context of H2020 MORPHEMIC project.
+ * @author Activeeon R&D Department
+ */
+
+@AllArgsConstructor
+public class WfAnalyserCamelUtils {
+
+ Element camelModelRoot;
+
+ public JSONArray getResourceRequirements(int reqIndex) {
+ JSONArray resourceRequirement = new JSONArray();
+ Element requirementModels = camelModelRoot.getChild("requirementModels");
+ // Get component Req by index
+ Element compRequirement = requirementModels.getChildren("requirements").get(reqIndex);
+ // Get component req features
+ List subFeatures = compRequirement.getChildren("subFeatures");
+ // Get list of attributes per component feature
+ for(Element feature: subFeatures) {
+ JSONObject requirement = new JSONObject();
+ String reqName = feature.getAttributeValue("annotations");
+ // Get list of attributes per requirement element
+ List attributes = feature.getChildren("attributes");
+ JSONArray listOfRequirements = new JSONArray();
+ for(Element attribute: attributes) {
+ // Get attribute name
+ String attributeName = attribute.getAttributeValue("name");
+ // Get attribute value
+ String value = attribute.getChild("value").getAttributeValue("value");
+ JSONObject attributeValue = new JSONObject();
+ // Create json object with attribute name and value
+ attributeValue.put(attributeName, value);
+ // Add the attribute object to the list
+ listOfRequirements.put(attributeValue);
+ }
+ requirement.put(reqName, listOfRequirements);
+ resourceRequirement.put(requirement);
+ }
+ return resourceRequirement;
+ }
+
+
+ public JSONArray getAppRequirements(int startIndex) {
+ JSONArray appRequirements = new JSONArray();
+ Element requirementModels = camelModelRoot.getChild("requirementModels");
+ // Get component Req
+ List compRequirements = requirementModels.getChildren("requirements");
+ for(int i=startIndex; i images = requirement.getChildren("images");
+ JSONArray imagesValue = new JSONArray();
+ for(Element image: images) {
+ imagesValue.put(image.getValue());
+ }
+
+ if(imagesValue.length()>0) {
+ instancesRequirementObject.put("Images for: " + reqName, imagesValue);
+ }
+
+ if(!instancesReq.isEmpty()) {
+ instancesRequirementObject.put(reqName, instancesReq);
+ }
+
+ //instancesRequirementObject.get()
+
+ if(!instancesRequirementObject.isEmpty()) {
+ appRequirements.put(instancesRequirementObject);
+ }
+ }
+ return appRequirements;
+ }
+
+
+ public JSONArray getWorkflowArchitecture() {
+ JSONArray results = new JSONArray();
+ List components = camelModelRoot.getChild("deploymentModels").getChildren("softwareComponents");
+ for(Element component: components) {
+ JSONArray cnx = new JSONArray();
+ List requiredCommunications = component.getChildren("requiredCommunications");
+ List providedCommunications = component.getChildren("providedCommunications");
+ for(Element requiredCommunication: requiredCommunications) {
+ String connectionName = WfAnalyserXmiElementUtils.findProvidedComponent(components, requiredCommunication.getAttributeValue("portNumber"));
+ if(!connectionName.isEmpty()) {
+ cnx.put(connectionName);
+ }
+ }
+ for(Element providedCommunication: providedCommunications) {
+ String connectionName = WfAnalyserXmiElementUtils.findProvidedComponent(components, providedCommunication.getAttributeValue("portNumber"));
+ if(!connectionName.isEmpty()) {
+ cnx.put(connectionName);
+ }
+ }
+ JSONObject compConnections = new JSONObject();
+ compConnections.put(component.getAttributeValue("name"), cnx);
+ results.put(compConnections);
+ }
+ return results;
+ }
+
+
+}
diff --git a/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/workflow/analyser/WfAnalyserXmiElementUtils.java b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/workflow/analyser/WfAnalyserXmiElementUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..6ca625ebefb10b0470f4425ab38aa6629b4696c6
--- /dev/null
+++ b/scheduling-abstraction-layer/src/main/java/org/activeeon/morphemic/workflow/analyser/WfAnalyserXmiElementUtils.java
@@ -0,0 +1,50 @@
+package org.activeeon.morphemic.workflow.analyser;
+
+import org.jdom2.Element;
+import org.json.JSONArray;
+
+import java.util.List;
+
+/*
+ * This class contains the methods that handle XMI elements to generate the corresponding JSON objects.
+ *
+ * Developed by Activeeon in the context of H2020 MORPHEMIC project.
+ * @author Activeeon R&D Department
+ */
+
+public class WfAnalyserXmiElementUtils {
+
+
+ public static String findRequiredComponent(List components, String portNumber) {
+ for(Element component: components) {
+ if(component.getChildren("providedCommunications").stream().anyMatch(provComm -> provComm.getAttributeValue("portNumber").equals(portNumber))) {
+ return component.getAttributeValue("name");
+ }
+ }
+ return "";
+ }
+
+ public static String findProvidedComponent(List components, String portNumber) {
+ for(Element component: components) {
+ if(component.getChildren("requiredCommunications").stream().anyMatch(provComm -> provComm.getAttributeValue("portNumber").equals(portNumber))) {
+ return component.getAttributeValue("name");
+ }
+ }
+ return "";
+ }
+
+ public static JSONArray getVariants(Element component) {
+ JSONArray variants = new JSONArray();
+ List attributes = component.getChildren("attributes");
+ for(Element element: attributes) {
+ String value = element.getChild("value").getAttributeValue("value");
+ if(value.contains("VM") || value.contains("DOCKER") || value.contains("SERVERLESS") || value.contains("HPC")) {
+ variants.put(value);
+ }
+ }
+ return variants;
+ }
+
+ private WfAnalyserXmiElementUtils() {}
+
+}