diff --git a/dmnverifierapi/pom.xml b/dmnverifierapi/pom.xml index d7ed68a707c9396870a239e999a83ef9cf43cbb9..c6cfe0d6863951949f1e1cd92b32e5b3cae05d72 100644 --- a/dmnverifierapi/pom.xml +++ b/dmnverifierapi/pom.xml @@ -42,10 +42,6 @@ <version>${version.camunda}</version> </dependency> <!-- Quarkus --> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy-jsonb</artifactId> - </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/SubsumptionVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/SubsumptionVerifier.java index fe62a425a134a5910eaaefd605dbbbfe2d677d4a..e3606793ed272bce84e50cc9cb9b8bcc7064b58a 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/SubsumptionVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/SubsumptionVerifier.java @@ -60,9 +60,7 @@ public class SubsumptionVerifier extends AbstractVerifier { vreFactory.addVerificationFix(SHOW_RULES); vreFactory.addToEntry( VerificationClassification.WARNING, - templateDecision(inColumns.get(0).getDmnDecision()) - + getMessageText( - currentRules, currentRootSubsumptionElements, differentConclusions)); + getMessageText(currentRules, currentRootSubsumptionElements, differentConclusions)); } } else { // get all input values from the current column, and filter with the prev. iteration diff --git a/dmnverifierfrontend/src/main/java/de/unikoblenz/fgbks/dmn/frontend/DmnBean.java b/dmnverifierfrontend/src/main/java/de/unikoblenz/fgbks/dmn/frontend/DmnBean.java index beb00ab80414535311938b4d899c494cb430e5cb..58f01578dbff91f173cf45a29b9ba562ac40ca1a 100644 --- a/dmnverifierfrontend/src/main/java/de/unikoblenz/fgbks/dmn/frontend/DmnBean.java +++ b/dmnverifierfrontend/src/main/java/de/unikoblenz/fgbks/dmn/frontend/DmnBean.java @@ -2,10 +2,15 @@ package de.unikoblenz.fgbks.dmn.frontend; import java.io.Serializable; import javax.enterprise.context.SessionScoped; +import javax.json.bind.annotation.JsonbProperty; @SessionScoped public class DmnBean implements Serializable { + @JsonbProperty("camundaUrl") + protected String camundaUrl = ""; + + @JsonbProperty("dmnXml") protected String dmnXml; public String getDmnXml() { @@ -15,4 +20,12 @@ public class DmnBean implements Serializable { public void setDmnXml(String dmnXml) { this.dmnXml = dmnXml; } + + public String getCamundaUrl() { + return camundaUrl; + } + + public void setCamundaUrl(String camundaUrl) { + this.camundaUrl = camundaUrl; + } } diff --git a/dmnverifierfrontend/src/main/java/de/unikoblenz/fgbks/dmn/frontend/DmnSessionApi.java b/dmnverifierfrontend/src/main/java/de/unikoblenz/fgbks/dmn/frontend/DmnSessionApi.java index 3b316f5840929a1e0912035ec73ea0f1a3cccdbe..08dc705f4564eca81fda908d5aa53883653d79fc 100644 --- a/dmnverifierfrontend/src/main/java/de/unikoblenz/fgbks/dmn/frontend/DmnSessionApi.java +++ b/dmnverifierfrontend/src/main/java/de/unikoblenz/fgbks/dmn/frontend/DmnSessionApi.java @@ -16,19 +16,25 @@ public class DmnSessionApi { DmnBean dmnBean; @GET - @Path("/getdmn") - @Produces(MediaType.TEXT_XML) + @Produces(MediaType.APPLICATION_JSON) public Response getSessionDmn() { if (dmnBean.getDmnXml() == null) { return Response.noContent().build(); } - return Response.ok(dmnBean.getDmnXml()).build(); + return Response.ok(dmnBean).build(); } @POST - @Path("/setdmn") + @Path("/setDmn") @Consumes(MediaType.TEXT_XML) public void setSessionDmn(String dmnXml) { dmnBean.setDmnXml(dmnXml); } + + @POST + @Path("/setCamundaUrl") + @Consumes(MediaType.TEXT_PLAIN) + public void setCamundaUrl(String camundaUrl) { + dmnBean.setCamundaUrl(camundaUrl); + } } diff --git a/dmnverifierfrontend/src/main/resources/META-INF/resources/css/img/camundaConnect.png b/dmnverifierfrontend/src/main/resources/META-INF/resources/css/img/camundaConnect.png new file mode 100644 index 0000000000000000000000000000000000000000..490d9a822b78c19360205616ff3389f7609bffd4 Binary files /dev/null and b/dmnverifierfrontend/src/main/resources/META-INF/resources/css/img/camundaConnect.png differ diff --git a/dmnverifierfrontend/src/main/resources/META-INF/resources/css/stylesheets.css b/dmnverifierfrontend/src/main/resources/META-INF/resources/css/stylesheets.css index fc98b25c009326c533f127b6e6e7b50a98a84d69..b356d7ad4b8c0b948bd5b06d322347db5a6c1439 100644 --- a/dmnverifierfrontend/src/main/resources/META-INF/resources/css/stylesheets.css +++ b/dmnverifierfrontend/src/main/resources/META-INF/resources/css/stylesheets.css @@ -14,6 +14,10 @@ h1 { color: #0b3004; } +button { + background-color: white; +} + h2 { margin: 10px; } @@ -84,6 +88,7 @@ span.select2 { .clickable { box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, .3); + cursor: pointer; } .clickable:hover { @@ -101,12 +106,13 @@ span.select2 { } .dmn-top { - height: 60px; padding-left: 6px; padding-top: 6px; display: flex; flex-direction: row; + flex-wrap: wrap; justify-content: space-around; + margin-bottom: 5px; } .dmn-top-item { @@ -124,6 +130,7 @@ span.select2 { display: block; background-size: cover; background-position: center; + cursor: pointer; } .dmn-upload { @@ -154,6 +161,30 @@ span.select2 { width: 50px; } +.dmn-camunda-api { + flex-grow: 1; +} + +.dmn-camunda-api > label { + background-image: url("img/camundaConnect.png"); + width: 50px; +} + +.dmn-camunda-api > label > a { + display: inline-block; + width: 100%; + height: 100%; +} + +/** Modal */ +.modal-element { + width: 100%; + margin: 5px; + min-height: 25px; + padding: 5px; + font: 12pt Calibri; +} + /** Verifier configuration */ #dmn-verifier-header { @@ -167,14 +198,12 @@ span.select2 { #dmn-button-verify { flex-grow: 1; max-width: 90px; - background: white; border-radius: 2px; } #dmn-button-reload-verifier { flex-grow: 1; max-width: 120px; - background: white; border-radius: 2px; } @@ -182,7 +211,6 @@ span.select2 { margin: 8px 12px; color: #0b3004; min-height: 35px; - cursor: pointer; font-family: 'Open Sans', sans-serif; font-size: 13px; } @@ -268,5 +296,4 @@ span.select2 { height: 25px; min-width: 100px; margin: 2px 2px 2px 10px; - background: white; } diff --git a/dmnverifierfrontend/src/main/resources/META-INF/resources/dmn/emptyDMN.dmn b/dmnverifierfrontend/src/main/resources/META-INF/resources/dmn/emptyDMN.dmn index 73f512d15fe89bed7f3029e37912e153ce10ef34..f6fbeeac420da80fc9bf42df7cd00b2e662b2547 100644 --- a/dmnverifierfrontend/src/main/resources/META-INF/resources/dmn/emptyDMN.dmn +++ b/dmnverifierfrontend/src/main/resources/META-INF/resources/dmn/emptyDMN.dmn @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<definitions xmlns="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:biodi="http://bpmn.io/schema/dmn/biodi/1.0" id="Definitions_1kjh9a2" name="DRD" namespace="http://camunda.org/schema/1.0/dmn"> - <decision id="Decision_13nychf" name="Decision 1"> +<definitions xmlns="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:biodi="http://bpmn.io/schema/dmn/biodi/1.0" id="Definitions_genid1" name="DRD" namespace="http://camunda.org/schema/1.0/dmn"> + <decision id="Decision_genid2" name="Decision 1"> <extensionElements> <biodi:bounds x="120" y="145" width="180" height="80" /> </extensionElements> diff --git a/dmnverifierfrontend/src/main/resources/META-INF/resources/index.html b/dmnverifierfrontend/src/main/resources/META-INF/resources/index.html index bf24bcf7181640dcf8cccac708a633d4306be9a6..d09c9f692541e92fe8fe18201712d8a3934630f5 100644 --- a/dmnverifierfrontend/src/main/resources/META-INF/resources/index.html +++ b/dmnverifierfrontend/src/main/resources/META-INF/resources/index.html @@ -14,7 +14,8 @@ <link href="https://unpkg.com/dmn-js@7.0.1/dist/assets/dmn-js-literal-expression.css" rel="stylesheet"> <link href="https://unpkg.com/dmn-js@7.0.1/dist/assets/dmn-font/css/dmn.css" rel="stylesheet"> - + <link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.css" + rel="stylesheet"/> <link href="assets/css/select2.min.css" rel="stylesheet"/> <link href="css/stylesheets.css" rel="stylesheet" type="text/css"/> @@ -28,15 +29,20 @@ </label> <input id="dmn-file-upload" type="file"/> </div> + <div class="dmn-top-item dmn-download"> + <label class="clickable" for="dmn-file-download" title="Download current dmn"> + </label> + <input id="dmn-file-download" type="button"/> + </div> <div class="dmn-top-item dmn-empty-file"> <label class="clickable" for="dmn-file-empty" title="Create empty dmn"> </label> <input id="dmn-file-empty" type="button"/> </div> - <div class="dmn-top-item dmn-download"> - <label class="clickable" for="dmn-file-download" title="Download current dmn"> + <div class="dmn-top-item dmn-camunda-api"> + <label class="clickable" for="dmn-camunda-api" title="Connect to Camunda Engine"> + <a href="#modal-camunda-api" id="dmn-camunda-api" rel="modal:open"></a> </label> - <input id="dmn-file-download" type="button"/> </div> <div class="dmn-top-item"> <h1>Verification for Decision Modeling Notation</h1> @@ -53,14 +59,22 @@ </div> <div id="root-dmn-verifier"></div> </div> + +<!-- modal for camunda engine --> +<div class="modal" id="modal-camunda-api"> + <div id="camunda-api-root"></div> +</div> <!-- load jquery --> <script src="https://unpkg.com/jquery@3.4.1/dist/jquery.js" type="text/javascript"></script> <script src="assets/js/select2.full.min.js"></script> +<script + src="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.js"></script> <!-- load dmn modeler --> <script src="https://unpkg.com/dmn-js@7.0.1/dist/dmn-modeler.development.js"></script> <script src="js/dmnUpDownload.js" type="text/javascript"></script> <script src="js/dmnViewer.js" type="text/javascript"></script> <script src="js/dmnVerifier.js" type="text/javascript"></script> +<script src="js/dmnCamundaApi.js" type="text/javascript"></script> </body> </html> diff --git a/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnCamundaApi.js b/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnCamundaApi.js new file mode 100644 index 0000000000000000000000000000000000000000..98f1f42e09d193568dbb3177c598212a652bdc84 --- /dev/null +++ b/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnCamundaApi.js @@ -0,0 +1,198 @@ +const engineUrl = 'engine-rest/'; +let camundaEngineUrl = ''; +let connectionSuccess = false; +let $camundaApiRoot = $('#camunda-api-root'); +let $textCamundaUrl = $(` + <input class="modal-element" type="text" size="60"> +`); +$textCamundaUrl.val('localhost'); +let $buttonConnectCamundaUrl = $(` + <button class="clickable modal-element" size="60" id="camunda-connect" + onclick="connectCamunda()">Connect</button> +`); +let $selectCamundaDecisions = $( + `<select class="clickable modal-element" name="decisions" + id="select-camunda-decisions" + onchange="loadCamundaDecisionXml(this)"> + `); +let $buttonDeployDmn = $(` + <button class="clickable modal-element" size="60" id="camunda-connect" + onclick="deployDmn()">Deploy DMN</button> +`); +let $camundaApiContainer = $(`<div id="camunda-api-container">`); + +// register Button action +$(document).ready(function () { + clearCamundaApiRoot(); +}); + +function clearCamundaApiRoot() { + $camundaApiRoot.empty(); + $camundaApiRoot.append($(`<h2>Camunda DMN Deployment</h2>`)); + $camundaApiRoot.append($camundaApiContainer); + loadCamundaSessionParams(); +} + +function refreshParams() { + $textCamundaUrl.val(camundaEngineUrl); + $camundaApiContainer.empty(); + if (connectionSuccess) { + $camundaApiContainer.append($selectCamundaDecisions); + $camundaApiContainer.append($buttonDeployDmn); + } else { + $camundaApiContainer.append($textCamundaUrl); + $camundaApiContainer.append($buttonConnectCamundaUrl); + } +} + +function connectCamunda() { + camundaEngineUrl = $textCamundaUrl.val(); + if (!camundaEngineUrl.endsWith('/')) { + camundaEngineUrl += '/'; + } + if (!camundaEngineUrl.startsWith('http://')) { + camundaEngineUrl = 'http://' + camundaEngineUrl; + } + $textCamundaUrl.val(camundaEngineUrl); + requestOptionsCamundaDecisions(); +} + +function deployDmn() { + let dmnXml = exportDiagram(); + if (dmnXml) { + if (confirm("Do you really want to deploy this dmn?")) { + var fileStringArray = [dmnXml]; + + var fileName = "file.dmn"; + var blobAttrs = {type: "xml"}; + var file = new File(fileStringArray, fileName, blobAttrs); + + var formData = new FormData(); + formData.append("deployment-name", "test"); + formData.append("enable-duplicate-filtering", "true"); + formData.append("deployment-source", "process application"); + formData.append("data", file, file.name); + + $.ajax({ + url: camundaEngineUrl + engineUrl + "deployment/create", + type: "POST", + data: formData, + enctype: 'multipart/form-data', + async: true, + crossDomain: true, + processData: false, + contentType: false, + cache: false, + timeout: 0, + success: function (data) { + $.modal.close(); + requestOptionsCamundaDecisions(); + }, + error: function (e) { + alert("There was a error while deploying the dmn."); + } + }); + } + } +} + +function saveCamundaUrl() { + $.ajax({ + timeout: 1000, + url: "/dmn/setCamundaUrl", + type: 'POST', + contentType: 'text/plain', + data: $textCamundaUrl.val(), + error: function (err) { + // nothing + console.log(err); + } + }); +} + +function loadCamundaSessionParams() { + $.ajax({ + timeout: 1000, + url: "/dmn", + type: 'GET', + contentType: 'application/json', + error: function (err) { + camundaEngineUrl = ''; + connectionSuccess = false; + + refreshParams(); + }, + success: function (data) { + if (data !== undefined && data.camundaUrl !== undefined) { + camundaEngineUrl = data.camundaUrl; + } else { + camundaEngineUrl = ''; + } + refreshParams(); + } + }); +} + +function requestOptionsCamundaDecisions() { + $selectCamundaDecisions.empty(); + $.ajax({ + timeout: 1000, + url: camundaEngineUrl + engineUrl + + 'decision-definition?latestVersion=true', + type: 'GET', + contentType: 'application/json', + error: function (err) { + connectionSuccess = false; + alert( + "Error: No connection to the camunda engine established. Check URL or CORS options."); + refreshParams(); + }, + success: function (data) { + connectionSuccess = true; + renderDecisionsOptions(data); + saveCamundaUrl(); + refreshParams(); + } + }); +} + +function renderDecisionsOptions(decisions) { + $selectCamundaDecisions.empty(); + $selectCamundaDecisions.append($(` + <option value="null" selected>Select a definition</option> + `)); + for (let i = 0; i < decisions.length; i++) { + let decision = decisions[i]; + $selectCamundaDecisions.append($(` + <option value="${decision.key}">${decision.name} (Version: ${decision.version})</option> + `)); + } +} + +function loadCamundaDecisionXml(decisionSelect) { + if (decisionSelect.value !== 'null') { + if (confirm( + 'Do you really want to load the dmn "' + + $("#select-camunda-decisions option:selected").text() + + '"?')) { + $.ajax({ + timeout: 1000, + url: camundaEngineUrl + engineUrl + 'decision-definition/key/' + + decisionSelect.value + + '/xml/', + type: 'GET', + error: function (err) { + console.log("error", err); + connectionSuccess = false; + refreshParams(); + alert(err); + }, + success: function (data) { + openDiagram(data.dmnXml); + refreshParams(); + $.modal.close(); + } + }); + } + } +} diff --git a/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnUpDownload.js b/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnUpDownload.js index 83295f03bbe4f855d2a6bf69d44f4caaad0ef8bb..d96a586f152c359a7f4b03d70820cc39b40d0d4b 100644 --- a/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnUpDownload.js +++ b/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnUpDownload.js @@ -21,8 +21,12 @@ function loadEmptyFile() { $.ajax({ url: 'dmn/emptyDMN.dmn', type: 'GET', + cache: false, contentType: 'text/xml', success: function (data) { + // TODO, replace definition ID + data = data.replace("genid1", generateId(8)) + .replace("genid2", generateId(8)); openDiagram(data); } }); @@ -48,9 +52,9 @@ let oSerializer = new XMLSerializer(); function loadSessionDmn() { $.ajax({ timeout: 1000, - url: "/dmn/getdmn", + url: "/dmn", type: 'GET', - contentType: 'text/xml', + contentType: 'application/json', error: function (err) { // nothing console.log(">-->--> loading session dmn failed. <--<--<"); @@ -58,8 +62,13 @@ function loadSessionDmn() { loadEmptyFile(); }, success: function (data) { - let sXML = oSerializer.serializeToString(data); - openDiagram(sXML); + if (data !== undefined && data.dmnXml !== undefined) { + // let sXML = oSerializer.serializeToString(data.dmnXml); + let sXML = data.dmnXml; + openDiagram(sXML); + } else { + loadEmptyFile(); + } } }); } @@ -68,7 +77,7 @@ function saveSessionDmn() { let dmnXml = exportDiagram(); $.ajax({ timeout: 1000, - url: "/dmn/setdmn", + url: "/dmn/setDmn", type: 'POST', contentType: 'text/xml', data: dmnXml, @@ -78,3 +87,13 @@ function saveSessionDmn() { } }); } + +function generateId(length) { + var result = ''; + var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + var charactersLength = characters.length; + for (var i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; +} diff --git a/dmnverifierparent/pom.xml b/dmnverifierparent/pom.xml index ee94bcb972cc8b36907e76b4a9e649e3736cfeaa..0e5861a2794e82650860589988c9fca84b790237 100644 --- a/dmnverifierparent/pom.xml +++ b/dmnverifierparent/pom.xml @@ -37,6 +37,10 @@ <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy</artifactId> </dependency> + <dependency> + <artifactId>quarkus-resteasy-jsonb</artifactId> + <groupId>io.quarkus</groupId> + </dependency> </dependencies> <modules>