Skip to content
Snippets Groups Projects
Commit 6092c846 authored by Jonas Blatt's avatar Jonas Blatt :ant:
Browse files

Add camunda engine synchronisation of dmn definitions for continuous integration

parent 592110e6
No related branches found
No related tags found
No related merge requests found
Showing
with 302 additions and 27 deletions
...@@ -42,10 +42,6 @@ ...@@ -42,10 +42,6 @@
<version>${version.camunda}</version> <version>${version.camunda}</version>
</dependency> </dependency>
<!-- Quarkus --> <!-- Quarkus -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId> <artifactId>quarkus-junit5</artifactId>
......
...@@ -60,9 +60,7 @@ public class SubsumptionVerifier extends AbstractVerifier { ...@@ -60,9 +60,7 @@ public class SubsumptionVerifier extends AbstractVerifier {
vreFactory.addVerificationFix(SHOW_RULES); vreFactory.addVerificationFix(SHOW_RULES);
vreFactory.addToEntry( vreFactory.addToEntry(
VerificationClassification.WARNING, VerificationClassification.WARNING,
templateDecision(inColumns.get(0).getDmnDecision()) getMessageText(currentRules, currentRootSubsumptionElements, differentConclusions));
+ getMessageText(
currentRules, currentRootSubsumptionElements, differentConclusions));
} }
} else { } else {
// get all input values from the current column, and filter with the prev. iteration // get all input values from the current column, and filter with the prev. iteration
......
...@@ -2,10 +2,15 @@ package de.unikoblenz.fgbks.dmn.frontend; ...@@ -2,10 +2,15 @@ package de.unikoblenz.fgbks.dmn.frontend;
import java.io.Serializable; import java.io.Serializable;
import javax.enterprise.context.SessionScoped; import javax.enterprise.context.SessionScoped;
import javax.json.bind.annotation.JsonbProperty;
@SessionScoped @SessionScoped
public class DmnBean implements Serializable { public class DmnBean implements Serializable {
@JsonbProperty("camundaUrl")
protected String camundaUrl = "";
@JsonbProperty("dmnXml")
protected String dmnXml; protected String dmnXml;
public String getDmnXml() { public String getDmnXml() {
...@@ -15,4 +20,12 @@ public class DmnBean implements Serializable { ...@@ -15,4 +20,12 @@ public class DmnBean implements Serializable {
public void setDmnXml(String dmnXml) { public void setDmnXml(String dmnXml) {
this.dmnXml = dmnXml; this.dmnXml = dmnXml;
} }
public String getCamundaUrl() {
return camundaUrl;
}
public void setCamundaUrl(String camundaUrl) {
this.camundaUrl = camundaUrl;
}
} }
...@@ -16,19 +16,25 @@ public class DmnSessionApi { ...@@ -16,19 +16,25 @@ public class DmnSessionApi {
DmnBean dmnBean; DmnBean dmnBean;
@GET @GET
@Path("/getdmn") @Produces(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_XML)
public Response getSessionDmn() { public Response getSessionDmn() {
if (dmnBean.getDmnXml() == null) { if (dmnBean.getDmnXml() == null) {
return Response.noContent().build(); return Response.noContent().build();
} }
return Response.ok(dmnBean.getDmnXml()).build(); return Response.ok(dmnBean).build();
} }
@POST @POST
@Path("/setdmn") @Path("/setDmn")
@Consumes(MediaType.TEXT_XML) @Consumes(MediaType.TEXT_XML)
public void setSessionDmn(String dmnXml) { public void setSessionDmn(String dmnXml) {
dmnBean.setDmnXml(dmnXml); dmnBean.setDmnXml(dmnXml);
} }
@POST
@Path("/setCamundaUrl")
@Consumes(MediaType.TEXT_PLAIN)
public void setCamundaUrl(String camundaUrl) {
dmnBean.setCamundaUrl(camundaUrl);
}
} }
dmnverifierfrontend/src/main/resources/META-INF/resources/css/img/camundaConnect.png

17.2 KiB

...@@ -14,6 +14,10 @@ h1 { ...@@ -14,6 +14,10 @@ h1 {
color: #0b3004; color: #0b3004;
} }
button {
background-color: white;
}
h2 { h2 {
margin: 10px; margin: 10px;
} }
...@@ -84,6 +88,7 @@ span.select2 { ...@@ -84,6 +88,7 @@ span.select2 {
.clickable { .clickable {
box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, .3); box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, .3);
cursor: pointer;
} }
.clickable:hover { .clickable:hover {
...@@ -101,12 +106,13 @@ span.select2 { ...@@ -101,12 +106,13 @@ span.select2 {
} }
.dmn-top { .dmn-top {
height: 60px;
padding-left: 6px; padding-left: 6px;
padding-top: 6px; padding-top: 6px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap;
justify-content: space-around; justify-content: space-around;
margin-bottom: 5px;
} }
.dmn-top-item { .dmn-top-item {
...@@ -124,6 +130,7 @@ span.select2 { ...@@ -124,6 +130,7 @@ span.select2 {
display: block; display: block;
background-size: cover; background-size: cover;
background-position: center; background-position: center;
cursor: pointer;
} }
.dmn-upload { .dmn-upload {
...@@ -154,6 +161,30 @@ span.select2 { ...@@ -154,6 +161,30 @@ span.select2 {
width: 50px; 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 */ /** Verifier configuration */
#dmn-verifier-header { #dmn-verifier-header {
...@@ -167,14 +198,12 @@ span.select2 { ...@@ -167,14 +198,12 @@ span.select2 {
#dmn-button-verify { #dmn-button-verify {
flex-grow: 1; flex-grow: 1;
max-width: 90px; max-width: 90px;
background: white;
border-radius: 2px; border-radius: 2px;
} }
#dmn-button-reload-verifier { #dmn-button-reload-verifier {
flex-grow: 1; flex-grow: 1;
max-width: 120px; max-width: 120px;
background: white;
border-radius: 2px; border-radius: 2px;
} }
...@@ -182,7 +211,6 @@ span.select2 { ...@@ -182,7 +211,6 @@ span.select2 {
margin: 8px 12px; margin: 8px 12px;
color: #0b3004; color: #0b3004;
min-height: 35px; min-height: 35px;
cursor: pointer;
font-family: 'Open Sans', sans-serif; font-family: 'Open Sans', sans-serif;
font-size: 13px; font-size: 13px;
} }
...@@ -268,5 +296,4 @@ span.select2 { ...@@ -268,5 +296,4 @@ span.select2 {
height: 25px; height: 25px;
min-width: 100px; min-width: 100px;
margin: 2px 2px 2px 10px; margin: 2px 2px 2px 10px;
background: white;
} }
<?xml version="1.0" encoding="UTF-8"?> <?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"> <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_13nychf" name="Decision 1"> <decision id="Decision_genid2" name="Decision 1">
<extensionElements> <extensionElements>
<biodi:bounds x="120" y="145" width="180" height="80" /> <biodi:bounds x="120" y="145" width="180" height="80" />
</extensionElements> </extensionElements>
......
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
<link href="https://unpkg.com/dmn-js@7.0.1/dist/assets/dmn-js-literal-expression.css" <link href="https://unpkg.com/dmn-js@7.0.1/dist/assets/dmn-js-literal-expression.css"
rel="stylesheet"> rel="stylesheet">
<link href="https://unpkg.com/dmn-js@7.0.1/dist/assets/dmn-font/css/dmn.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="assets/css/select2.min.css" rel="stylesheet"/>
<link href="css/stylesheets.css" rel="stylesheet" type="text/css"/> <link href="css/stylesheets.css" rel="stylesheet" type="text/css"/>
...@@ -28,15 +29,20 @@ ...@@ -28,15 +29,20 @@
</label> </label>
<input id="dmn-file-upload" type="file"/> <input id="dmn-file-upload" type="file"/>
</div> </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"> <div class="dmn-top-item dmn-empty-file">
<label class="clickable" for="dmn-file-empty" title="Create empty dmn"> <label class="clickable" for="dmn-file-empty" title="Create empty dmn">
</label> </label>
<input id="dmn-file-empty" type="button"/> <input id="dmn-file-empty" type="button"/>
</div> </div>
<div class="dmn-top-item dmn-download"> <div class="dmn-top-item dmn-camunda-api">
<label class="clickable" for="dmn-file-download" title="Download current dmn"> <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> </label>
<input id="dmn-file-download" type="button"/>
</div> </div>
<div class="dmn-top-item"> <div class="dmn-top-item">
<h1>Verification for Decision Modeling Notation</h1> <h1>Verification for Decision Modeling Notation</h1>
...@@ -53,14 +59,22 @@ ...@@ -53,14 +59,22 @@
</div> </div>
<div id="root-dmn-verifier"></div> <div id="root-dmn-verifier"></div>
</div> </div>
<!-- modal for camunda engine -->
<div class="modal" id="modal-camunda-api">
<div id="camunda-api-root"></div>
</div>
<!-- load jquery --> <!-- load jquery -->
<script src="https://unpkg.com/jquery@3.4.1/dist/jquery.js" type="text/javascript"></script> <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="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 --> <!-- load dmn modeler -->
<script src="https://unpkg.com/dmn-js@7.0.1/dist/dmn-modeler.development.js"></script> <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/dmnUpDownload.js" type="text/javascript"></script>
<script src="js/dmnViewer.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/dmnVerifier.js" type="text/javascript"></script>
<script src="js/dmnCamundaApi.js" type="text/javascript"></script>
</body> </body>
</html> </html>
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();
}
});
}
}
}
...@@ -21,8 +21,12 @@ function loadEmptyFile() { ...@@ -21,8 +21,12 @@ function loadEmptyFile() {
$.ajax({ $.ajax({
url: 'dmn/emptyDMN.dmn', url: 'dmn/emptyDMN.dmn',
type: 'GET', type: 'GET',
cache: false,
contentType: 'text/xml', contentType: 'text/xml',
success: function (data) { success: function (data) {
// TODO, replace definition ID
data = data.replace("genid1", generateId(8))
.replace("genid2", generateId(8));
openDiagram(data); openDiagram(data);
} }
}); });
...@@ -48,9 +52,9 @@ let oSerializer = new XMLSerializer(); ...@@ -48,9 +52,9 @@ let oSerializer = new XMLSerializer();
function loadSessionDmn() { function loadSessionDmn() {
$.ajax({ $.ajax({
timeout: 1000, timeout: 1000,
url: "/dmn/getdmn", url: "/dmn",
type: 'GET', type: 'GET',
contentType: 'text/xml', contentType: 'application/json',
error: function (err) { error: function (err) {
// nothing // nothing
console.log(">-->--> loading session dmn failed. <--<--<"); console.log(">-->--> loading session dmn failed. <--<--<");
...@@ -58,8 +62,13 @@ function loadSessionDmn() { ...@@ -58,8 +62,13 @@ function loadSessionDmn() {
loadEmptyFile(); loadEmptyFile();
}, },
success: function (data) { success: function (data) {
let sXML = oSerializer.serializeToString(data); if (data !== undefined && data.dmnXml !== undefined) {
openDiagram(sXML); // let sXML = oSerializer.serializeToString(data.dmnXml);
let sXML = data.dmnXml;
openDiagram(sXML);
} else {
loadEmptyFile();
}
} }
}); });
} }
...@@ -68,7 +77,7 @@ function saveSessionDmn() { ...@@ -68,7 +77,7 @@ function saveSessionDmn() {
let dmnXml = exportDiagram(); let dmnXml = exportDiagram();
$.ajax({ $.ajax({
timeout: 1000, timeout: 1000,
url: "/dmn/setdmn", url: "/dmn/setDmn",
type: 'POST', type: 'POST',
contentType: 'text/xml', contentType: 'text/xml',
data: dmnXml, data: dmnXml,
...@@ -78,3 +87,13 @@ function saveSessionDmn() { ...@@ -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;
}
...@@ -37,6 +37,10 @@ ...@@ -37,6 +37,10 @@
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId> <artifactId>quarkus-resteasy</artifactId>
</dependency> </dependency>
<dependency>
<artifactId>quarkus-resteasy-jsonb</artifactId>
<groupId>io.quarkus</groupId>
</dependency>
</dependencies> </dependencies>
<modules> <modules>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment