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() {} + +}