diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/deployment/WineryUtils.js b/components/bpmn-q/modeler-component/extensions/opentosca/deployment/WineryUtils.js
index dc1a6bf81..cb5e84d4b 100644
--- a/components/bpmn-q/modeler-component/extensions/opentosca/deployment/WineryUtils.js
+++ b/components/bpmn-q/modeler-component/extensions/opentosca/deployment/WineryUtils.js
@@ -208,7 +208,9 @@ export async function addNodeWithArtifactToServiceTemplateByName(
name,
artifactTemplateQName,
artifactName,
- artifactTypeQName
+ artifactTypeQName,
+ requirementTypes,
+ kvProperties
) {
const serviceTemplateAddress =
encodeURIComponent(encodeURIComponent(QUANTME_NAMESPACE_PUSH)) +
@@ -221,7 +223,9 @@ export async function addNodeWithArtifactToServiceTemplateByName(
name,
artifactTemplateQName,
artifactName,
- artifactTypeQName
+ artifactTypeQName,
+ requirementTypes,
+ kvProperties
);
return serviceTemplateAddress;
}
@@ -288,7 +292,9 @@ export async function addNodeWithArtifactToServiceTemplate(
name,
artifactTemplateQName,
artifactName,
- artifactTypeQName
+ artifactTypeQName,
+ requirementTypes,
+ kvProperties
) {
const nodeTemplate = {
documentation: [],
@@ -305,10 +311,7 @@ export async function addNodeWithArtifactToServiceTemplate(
},
properties: {
propertyType: "KV",
- kvproperties: {
- Port: "",
- Name: "",
- },
+ kvproperties: kvProperties,
elementName: "properties",
namespace:
"http://opentosca.org/nodetypes/propertiesdefinition/winery",
@@ -321,7 +324,7 @@ export async function addNodeWithArtifactToServiceTemplate(
x: 1245,
y: 350,
capabilities: [],
- requirements: [],
+ requirements: requirementTypes,
deploymentArtifacts: [
{
documentation: [],
@@ -391,16 +394,23 @@ export async function createServiceTemplateWithNodeAndArtifact(
nodeName,
artifactTemplateQName,
artifactName,
- artifactTypeQName
+ artifactTypeQName,
+ requirementTypes,
+ kvProperties
) {
- const serviceTemplateAddress = await createServiceTemplate(name);
+ const serviceTemplateAddress = await createServiceTemplate(
+ name,
+ "http://quantil.org/quantme/push"
+ );
await addNodeWithArtifactToServiceTemplate(
serviceTemplateAddress,
nodeTypeQName,
nodeName,
artifactTemplateQName,
artifactName,
- artifactTypeQName
+ artifactTypeQName,
+ requirementTypes,
+ kvProperties
);
return serviceTemplateAddress;
}
@@ -436,10 +446,41 @@ const nodeTypeQNameMapping = new Map([
"{http://opentosca.org/nodetypes}PythonApp_3-w1",
],
]);
+
+const artifactTypeKVMapping = new Map([
+ [
+ "WAR",
+ {
+ Port: "",
+ Name: "",
+ },
+ ],
+ [
+ "Python",
+ {
+ Port: "",
+ Name: "",
+ },
+ ],
+ [
+ "Flask",
+ {
+ StartupCommand:
+ "export FLASK_APP=app.py && export FLASK_ENV=development && export FLASK_DEBUG=0 && python3 -m flask run --host=0.0.0.0",
+ Name: "app",
+ },
+ ],
+]);
+
export function getNodeTypeQName(artifactTypeQName) {
return nodeTypeQNameMapping.get(artifactTypeQName);
}
+export function getArtifactTypeKVMapping(artifactType) {
+ console.log("retrieving kv mapping for type", artifactType);
+ return artifactTypeKVMapping.get(artifactType);
+}
+
export async function loadTopology(deploymentModelUrl) {
if (deploymentModelUrl.startsWith("{{ wineryEndpoint }}")) {
deploymentModelUrl = deploymentModelUrl.replace(
diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/ArtifactUploadModal.js b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/ArtifactUploadModal.js
index 501c20159..4e0e48c8c 100644
--- a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/ArtifactUploadModal.js
+++ b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/ArtifactUploadModal.js
@@ -18,6 +18,7 @@ import {
createArtifactTemplateWithFile,
createServiceTemplateWithNodeAndArtifact,
getNodeTypeQName,
+ getArtifactTypeKVMapping,
getArtifactTemplateInfo,
insertTopNodeTag,
serviceTemplateExists,
@@ -54,6 +55,9 @@ export default function ArtifactUploadModal({
const [selectedOption, setSelectedOption] = useState("");
const [selectedOptionName, setSelectedOptionName] = useState("");
const [artifactTypes, setArtifactTypes] = useState([]);
+ const [requirementTypes, setRequirementTypes] = useState([]);
+ const [kvProperties, setKvProperties] = useState({});
+ const [isFlask, setIsFlask] = useState(false);
const [acceptTypes, setAcceptTypes] = useState("");
async function updateArtifactSelect() {
@@ -101,9 +105,22 @@ export default function ArtifactUploadModal({
artifactTemplateAddress
);
const artifactTemplateQName =
+ "{" +
+ artifactTemplateInfo.targetNamespace +
+ "}" +
artifactTemplateInfo
- .serviceTemplateOrNodeTypeOrNodeTypeImplementation[0].type;
- const nodeTypeQName = getNodeTypeQName(selectedOption);
+ .serviceTemplateOrNodeTypeOrNodeTypeImplementation[0].id;
+ // artifactTemplateInfo.serviceTemplateOrNodeTypeOrNodeTypeImplementation[0].type;
+ let nodeTypeQName = getNodeTypeQName(selectedOption);
+ if (
+ isFlask &&
+ nodeTypeQName === "{http://opentosca.org/nodetypes}PythonApp_3-w1"
+ ) {
+ nodeTypeQName =
+ "{https://ust-quantil.github.io/nodetypes}QuokkaPythonApp_latest-w1-wip1";
+ }
+ console.log("nodetypeqname", nodeTypeQName);
+ console.log("kvproperties", kvProperties);
const serviceTemplateName = `${namePrefix}ServiceTemplate-${element.id}`;
const doesExist = await serviceTemplateExists(serviceTemplateName);
console.log("doesExist", doesExist);
@@ -115,7 +132,9 @@ export default function ArtifactUploadModal({
`${namePrefix}Node-${element.id}`,
artifactTemplateQName,
`${namePrefix}Artifact-${element.id}`,
- selectedOption
+ selectedOption,
+ requirementTypes,
+ kvProperties
);
await deleteTopNodeTag(serviceTemplateAddress);
} else {
@@ -125,7 +144,9 @@ export default function ArtifactUploadModal({
`${namePrefix}Node-${element.id}`,
artifactTemplateQName,
`${namePrefix}Artifact-${element.id}`,
- selectedOption
+ selectedOption,
+ requirementTypes,
+ kvProperties
);
}
await insertTopNodeTag(serviceTemplateAddress, nodeTypeQName);
@@ -192,12 +213,36 @@ export default function ArtifactUploadModal({
setSelectedOptionName(artifactTypes.find((x) => x.qName === value).name);
if (value.includes("WAR")) {
setAcceptTypes(allowedFileTypes.war);
+ setRequirementTypes([]);
+ setKvProperties(getArtifactTypeKVMapping("WAR"));
} else if (value.includes("PythonArchive")) {
setAcceptTypes(allowedFileTypes.zip);
+ const pythonReq = {
+ name: "canHostPythonApp",
+ id: "req1",
+ type: "{https://ust-quantil.github.io/requirementtypes}ReqCanInstallQiskit",
+ };
+ setRequirementTypes([pythonReq]);
+ setKvProperties(getArtifactTypeKVMapping("Python"));
}
+ console.log("handle dropdown change");
};
const isOptionSelected = selectedOption !== "";
+ const isPythonArchive = selectedOption.includes("PythonArchive");
+
+ const handleIsFlaskCheckboxChange = () => {
+ setIsFlask(!isFlask);
+ let artifactType = "";
+ if (isFlask) {
+ // For some reason this works the other way round as expected
+ artifactType = "Python";
+ } else {
+ artifactType = "Flask";
+ }
+ console.log("artifacttype", artifactType);
+ setKvProperties(getArtifactTypeKVMapping(artifactType));
+ };
if (artifactTypes.length === 0) {
updateArtifactSelect();
@@ -252,6 +297,20 @@ export default function ArtifactUploadModal({
))}
+
+ {isOptionSelected && isPythonArchive && (
+
+
+
+
+
+
+ )}
{isOptionSelected && (
diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/Connector.js b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/Connector.js
index 6c2416415..a488e732c 100644
--- a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/Connector.js
+++ b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/Connector.js
@@ -93,15 +93,21 @@ export function Connector({ element, translate, filteredUrls, methodUrlList }) {
const setMethodValue = function (value) {
const moddle = getModeler().get("moddle");
- const entry = moddle.create(
- "camunda:Entry",
- { key: "Accept", value: "application/json" },
- { key: "Content-Type", value: "application/json" }
- );
+ const acceptEntry = moddle.create("camunda:Entry", {
+ key: "Accept",
+ value: "application/json",
+ });
+ const contentEntry = moddle.create("camunda:Entry", {
+ key: "Content-Type",
+ value: "application/json",
+ });
- const map = moddle.create("camunda:Map", { entries: [entry] });
+ const map = moddle.create("camunda:Map", {
+ entries: [acceptEntry, contentEntry],
+ });
- entry.$parent = map;
+ acceptEntry.$parent = map;
+ contentEntry.$parent = map;
const headersInputParameter = moddle.create("camunda:InputParameter", {
definition: map,
@@ -110,7 +116,7 @@ export function Connector({ element, translate, filteredUrls, methodUrlList }) {
const methodInputParameter = moddle.create("camunda:InputParameter", {
name: "method",
- value: value,
+ value: value.toUpperCase(),
});
const urlInputParameter = moddle.create("camunda:InputParameter", {
name: "url",
@@ -126,7 +132,6 @@ export function Connector({ element, translate, filteredUrls, methodUrlList }) {
const script = moddle.create("camunda:Script", {
scriptFormat: "Groovy",
value: scriptValue,
- resource: "Inline",
});
const payloadInputParameter = moddle.create("camunda:InputParameter", {
@@ -140,8 +145,11 @@ export function Connector({ element, translate, filteredUrls, methodUrlList }) {
inputParameters.push(payloadInputParameter);
let outputParameters = determineOutputParameters(
- element.businessObject.yaml
+ element.businessObject.yaml,
+ element.businessObject.connectorUrl,
+ value
);
+
let camundaOutputParameters =
constructCamundaOutputParameters(outputParameters);
@@ -245,88 +253,85 @@ function determineInputParameters(yamlData, schemePath, method) {
}
}
-function determineOutputParameters(yamlData) {
- // Parse the YAML data
+function determineOutputParameters(yamlData, schemePath, method) {
const data = yaml.load(yamlData);
-
- // Initialize an object to store the input parameters
let outputParameters = [];
- // Extract the request bodies and their parameters
- for (const methods of Object.values(data.paths)) {
- console.log(data.paths);
- for (const details of Object.values(methods)) {
- console.log(details);
- if (details.responses) {
- const response = details.responses;
- // Access the properties of the schema
- // Access the schema referenced by "200"
- const statusCode = "200";
- let responseStatusCode = statusCode;
-
- if (response[statusCode] === undefined) {
- // If the response for the specified status code is not defined
- // Find another response with a status code starting with 2
- responseStatusCode = Object.keys(response).find((code) =>
- code.startsWith("2")
- );
- console.log(responseStatusCode);
- }
+ const methods = data.paths[schemePath];
+ if (!methods || !methods[method]) return [];
- if (responseStatusCode !== undefined) {
- let schema =
- response[responseStatusCode].content["application/json"].schema;
- if (schema.$ref) {
- const schemaPath = schema.$ref
- .replace("#/", "")
- .replaceAll("/", ".");
- schema = getObjectByPath2(data, schemaPath);
- }
- // Function to access an object property by path
- // eslint-disable-next-line no-inner-declarations
- function getObjectByPath2(obj, path) {
- const parts = path.split(".");
- let currentObj = obj;
- for (const part of parts) {
- if (!currentObj || !currentObj.hasOwnProperty(part)) {
- return undefined;
- }
- currentObj = currentObj[part];
- }
- return currentObj;
- }
- // Access the properties of the schema
- outputParameters = Object.keys(schema.properties);
- }
- } else {
- return [];
+ const details = methods[method];
+
+ if (details.responses) {
+ const response = details.responses;
+ let responseStatusCode = "200";
+
+ if (!response[responseStatusCode]) {
+ responseStatusCode = Object.keys(response).find((code) =>
+ code.startsWith("2")
+ );
+ }
+
+ if (responseStatusCode && response[responseStatusCode]) {
+ let schema =
+ response[responseStatusCode].content?.["application/json"]?.schema;
+ if (!schema) return [];
+
+ if (schema.$ref) {
+ const schemaPath = schema.$ref.replace("#/", "").replaceAll("/", ".");
+ schema = getObjectByPath(yaml.load(yamlData), schemaPath);
+ }
+
+ if (schema?.properties) {
+ outputParameters = Object.keys(schema.properties);
}
}
}
+
return outputParameters;
+
+ function getObjectByPath(obj, path) {
+ return path.split(".").reduce((o, key) => (o ? o[key] : undefined), obj);
+ }
}
function constructCamundaOutputParameters(parameters) {
let outputParameters = [];
for (let param of parameters) {
let moddle = getModeler().get("moddle");
- const script = moddle.create("camunda:Script", {
- scriptFormat: "Groovy",
- value:
+ let scriptContent;
+ if (param === "visualization") {
+ scriptContent =
+ "import org.camunda.bpm.engine.variable.value.FileValue\n" +
+ "import org.camunda.bpm.engine.variable.Variables\n" +
+ "import groovy.json.JsonSlurper\n" +
+ 'def slurper = new JsonSlurper().parseText(connector.getVariable("response"))\n' +
+ 'String filename = "circuit.png"\n' +
+ "FileValue typedFileValue = Variables.fileValue(filename)\n" +
+ " .file(slurper.visualization.decodeBase64())\n" +
+ ' .mimeType("image/png")\n' +
+ " .create()\n" +
+ "return typedFileValue";
+ } else {
+ scriptContent =
'def resp = connector.getVariable("response");\n' +
"resp = new groovy.json.JsonSlurper().parseText(resp);\n" +
"def " +
param +
- " = resp.get(" +
+ ' = resp.get("' +
param +
- ");\n" +
+ '");\n' +
"println(" +
param +
");\n" +
"return " +
param +
- ";",
- resource: "Inline",
+ ";";
+ }
+
+ const script = moddle.create("camunda:Script", {
+ scriptFormat: "Groovy",
+ value: scriptContent,
});
const outputParameter = moddle.create("camunda:OutputParameter", {
diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/artifact-modal.css b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/artifact-modal.css
index f63ac4ee3..cd6d36024 100644
--- a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/artifact-modal.css
+++ b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/properties-provider/artifact-modal.css
@@ -101,6 +101,13 @@
text-overflow: ellipsis;
}
+.set-flask {
+ flex: 1;
+ max-width: 282px;
+ overflow: clip;
+ text-overflow: ellipsis;
+}
+
.upload-file-upload-button {
overflow: hidden;
text-overflow: ellipsis;
diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/replacement/OnDemandTransformator.js b/components/bpmn-q/modeler-component/extensions/opentosca/replacement/OnDemandTransformator.js
index 3cc053ca3..6e4e193d8 100644
--- a/components/bpmn-q/modeler-component/extensions/opentosca/replacement/OnDemandTransformator.js
+++ b/components/bpmn-q/modeler-component/extensions/opentosca/replacement/OnDemandTransformator.js
@@ -199,8 +199,20 @@ try {
println post;
println post.getInputStream();
def location = post.getHeaderFields()['Location'][0];
+ println("retrieved location with possibly wrong ip and port: " + location);
+
+ // Parse both URLs
+ def correctBase = new URL(url).getProtocol() + "://" + new URL(url).getAuthority()
+ def brokenPath = new URL(location).getPath()
+
+ // Construct the fixed URL
+ def fixedLocation= correctBase + brokenPath
+ println("Fixed location of completed deployment model: "+ fixedLocation)
+
+
def saveVarName = "completeModelUrl_" + "${taskId}";
- execution.setVariable(saveVarName, location);
+ execution.setVariable(saveVarName, fixedLocation);
+ println("Set completed deploymentmodel location with variable name: " + saveVarName + " and value: " + fixedLocation);
}else{
throw new org.camunda.bpm.engine.delegate.BpmnError("Received status code " + status + " while completing Deployment Model!");
}
@@ -219,6 +231,7 @@ function createCheckForEquivalencyScript(taskId) {
import groovy.json.*
def url = execution.getVariable("completeModelUrl_" + "${taskId}");
url = url + "topologytemplate/checkforequivalentcsars?includeSelf=true"
+println("Check for equivalent Csars at: " + url);
try {
def post = new URL(url).openConnection();
@@ -239,7 +252,7 @@ try {
def saveVarName = "equivalentCSARs_" + "${taskId}";
execution.setVariable(saveVarName, json);
}else{
- throw new org.camunda.bpm.engine.delegate.BpmnError("Received status code " + status + " while completing Deployment Model!");
+ throw new org.camunda.bpm.engine.delegate.BpmnError("Received status code " + status + " while checking for equivalent Deployment Model!");
}
} catch(org.camunda.bpm.engine.delegate.BpmnError e) {
println e.errorCode;
diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/ui/deployment/services/DeploymentPlugin.js b/components/bpmn-q/modeler-component/extensions/opentosca/ui/deployment/services/DeploymentPlugin.js
index 91e8949e7..10bd26a86 100644
--- a/components/bpmn-q/modeler-component/extensions/opentosca/ui/deployment/services/DeploymentPlugin.js
+++ b/components/bpmn-q/modeler-component/extensions/opentosca/ui/deployment/services/DeploymentPlugin.js
@@ -497,7 +497,7 @@ export default class DeploymentPlugin extends PureComponent {
);
// complete CSAR and refresh meta data
- const locationOfCompletedCSAR = completeIncompleteDeploymentModel(
+ let locationOfCompletedCSAR = completeIncompleteDeploymentModel(
csar.url,
blacklistedNodetypes,
policies
@@ -527,7 +527,10 @@ export default class DeploymentPlugin extends PureComponent {
.split("/")
.filter((x) => x.length > 1)
.pop();
- csar.url = locationOfCompletedCSAR + "?csar";
+ csar.url =
+ getWineryEndpoint() +
+ locationOfCompletedCSAR.split("/winery").pop() +
+ "?csar";
csar.csarName = nameOfCompletedCSAR + ".csar";
csar.incomplete = false;
console.log("Completed CSAR. New name: ", csar.csarName);