diff --git a/.ci/jenkins/Jenkinsfile.deploy b/.ci/jenkins/Jenkinsfile.deploy index 58e0c532bb..51afe0271e 100644 --- a/.ci/jenkins/Jenkinsfile.deploy +++ b/.ci/jenkins/Jenkinsfile.deploy @@ -119,7 +119,9 @@ pipeline { if (isRelease()) { releaseUtils.gpgImportKeyFromStringWithoutPassword(getReleaseGpgSignKeyCredsId()) - mavenCommand.withProfiles(['apache-release']) + mavenCommand + .withProfiles(['apache-release']) + .withProperty('only.reproducible') } configFileProvider([configFile(fileId: env.MAVEN_SETTINGS_CONFIG_FILE_ID, variable: 'MAVEN_SETTINGS_FILE')]) { diff --git a/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-embedded/pom.xml b/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-embedded/pom.xml index 72383b29ad..d244649644 100644 --- a/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-embedded/pom.xml +++ b/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-embedded/pom.xml @@ -100,18 +100,39 @@ + + maven-resources-plugin + + + generate-resources + + copy-resources + + + ${project.basedir}/src/main/resources/shared + + + ${common.test.resources.dir} + + **/*.bpmn + **/*.sw.json + + + + + + + + + maven-clean-plugin + + + + ${project.basedir}/src/main/resources/shared + + + + - - - src/main/resources - - - ${common.test.resources.dir} - - **/*.bpmn - **/*.sw.json - - - diff --git a/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-knative-eventing/pom.xml b/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-knative-eventing/pom.xml index 309ff02dcb..e105b0f06a 100644 --- a/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-knative-eventing/pom.xml +++ b/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-knative-eventing/pom.xml @@ -88,18 +88,39 @@ + + maven-resources-plugin + + + generate-resources + + copy-resources + + + ${project.basedir}/src/main/resources/shared + + + ${common.test.resources.dir} + + **/*.bpmn + **/*.sw.json + + + + + + + + + maven-clean-plugin + + + + ${project.basedir}/src/main/resources/shared + + + + - - - src/main/resources - - - ${common.test.resources.dir} - - **/*.bpmn - **/*.sw.json - - - diff --git a/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-management/pom.xml b/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-management/pom.xml index ade7cbe17e..6cccd4aa7a 100644 --- a/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-management/pom.xml +++ b/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-management/pom.xml @@ -79,7 +79,6 @@ io.quarkus quarkus-maven-plugin - ${version.io.quarkus} true @@ -91,18 +90,39 @@ + + maven-resources-plugin + + + generate-resources + + copy-resources + + + ${project.basedir}/src/main/resources/shared + + + ${common.test.resources.dir} + + **/*.bpmn + **/*.sw.json + + + + + + + + + maven-clean-plugin + + + + ${project.basedir}/src/main/resources/shared + + + + - - - src/main/resources - - - ${common.test.resources.dir} - - **/*.bpmn - **/*.sw.json - - - diff --git a/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-messaging/pom.xml b/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-messaging/pom.xml index 3ccd6395dd..fba2a2c5f1 100644 --- a/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-messaging/pom.xml +++ b/apps-integration-tests/integration-tests-jobs-service/integration-tests-jobs-service-quarkus/integration-tests-jobs-service-quarkus-messaging/pom.xml @@ -94,24 +94,10 @@ - - - src/main/resources - - - ${common.test.resources.dir} - - **/*.bpmn - **/*.sw.json - - - - io.quarkus quarkus-maven-plugin - ${version.io.quarkus} true @@ -123,6 +109,39 @@ + + maven-resources-plugin + + + generate-resources + + copy-resources + + + ${project.basedir}/src/main/resources/shared + + + ${common.test.resources.dir} + + **/*.bpmn + **/*.sw.json + + + + + + + + + maven-clean-plugin + + + + ${project.basedir}/src/main/resources/shared + + + + diff --git a/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-common/pom.xml b/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-common/pom.xml index 1ad411f350..9aafdb5dad 100644 --- a/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-common/pom.xml +++ b/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-common/pom.xml @@ -87,10 +87,6 @@ kogito-test-utils compile - - org.keycloak - keycloak-core - diff --git a/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-common/src/main/java/org/kie/kogito/it/trusty/AbstractTrustyExplainabilityEnd2EndIT.java b/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-common/src/main/java/org/kie/kogito/it/trusty/AbstractTrustyExplainabilityEnd2EndIT.java index 4207ff9ae6..0ce911613a 100644 --- a/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-common/src/main/java/org/kie/kogito/it/trusty/AbstractTrustyExplainabilityEnd2EndIT.java +++ b/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-common/src/main/java/org/kie/kogito/it/trusty/AbstractTrustyExplainabilityEnd2EndIT.java @@ -29,7 +29,6 @@ import java.util.stream.Collectors; import org.junit.jupiter.api.Test; -import org.keycloak.representations.AccessTokenResponse; import org.kie.kogito.explainability.api.CounterfactualSearchDomain; import org.kie.kogito.explainability.api.CounterfactualSearchDomainCollectionValue; import org.kie.kogito.explainability.api.CounterfactualSearchDomainStructureValue; @@ -183,7 +182,7 @@ public void doTest() { .param(KEYCLOAK_CLIENT_SECRET_PARAM_NAME, KEYCLOAK_CLIENT_SECRET_PARAM_VALUE) .when() .post(KEYCLOAK_ACCESS_TOKEN_PATH) - .as(AccessTokenResponse.class).getToken(); + .jsonPath().get("access_token"); assertNotNull(accessToken); diff --git a/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-springboot/pom.xml b/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-springboot/pom.xml index 2340d6020b..5219530993 100644 --- a/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-springboot/pom.xml +++ b/apps-integration-tests/integration-tests-trusty-service/integration-tests-trusty-service-springboot/pom.xml @@ -33,7 +33,7 @@ org.kie.kogito/integration-tests-trusty-service-springboot:${project.version} **/KogitoApplication.java - 3.3.1 + 3.4.4 eclipse-temurin:17-jre diff --git a/data-index/data-index-graphql/src/main/resources/basic.schema.graphqls b/data-index/data-index-graphql/src/main/resources/basic.schema.graphqls index 741c0d4e89..0317ec61c5 100644 --- a/data-index/data-index-graphql/src/main/resources/basic.schema.graphqls +++ b/data-index/data-index-graphql/src/main/resources/basic.schema.graphqls @@ -96,6 +96,7 @@ type ProcessInstance { identity: String createdBy: String updatedBy: String + slaDueDate: DateTime } type ProcessInstanceError { @@ -135,6 +136,7 @@ type NodeInstance { exit: DateTime definitionId: String! nodeId: String! + slaDueDate: DateTime } enum MilestoneStatus { diff --git a/data-index/data-index-service/data-index-service-common/pom.xml b/data-index/data-index-service/data-index-service-common/pom.xml index a3eb73abd7..4abb945f17 100644 --- a/data-index/data-index-service/data-index-service-common/pom.xml +++ b/data-index/data-index-service/data-index-service-common/pom.xml @@ -141,11 +141,6 @@ json-unit-assertj test - - org.keycloak - keycloak-core - test - org.kie.kogito kogito-quarkus-test-utils diff --git a/data-index/data-index-service/data-index-service-common/src/test/java/org/kie/kogito/index/service/AbstractKeycloakIntegrationIndexingServiceIT.java b/data-index/data-index-service/data-index-service-common/src/test/java/org/kie/kogito/index/service/AbstractKeycloakIntegrationIndexingServiceIT.java index f2fcd37cd0..c91e5195a5 100644 --- a/data-index/data-index-service/data-index-service-common/src/test/java/org/kie/kogito/index/service/AbstractKeycloakIntegrationIndexingServiceIT.java +++ b/data-index/data-index-service/data-index-service-common/src/test/java/org/kie/kogito/index/service/AbstractKeycloakIntegrationIndexingServiceIT.java @@ -20,7 +20,6 @@ import org.eclipse.microprofile.config.inject.ConfigProperty; import org.junit.jupiter.api.Test; -import org.keycloak.representations.AccessTokenResponse; import org.kie.kogito.testcontainers.KogitoKeycloakContainer; import org.kie.kogito.testcontainers.quarkus.KeycloakQuarkusTestResource; @@ -97,6 +96,6 @@ private String getAccessToken(String userName) { .param("client_secret", KogitoKeycloakContainer.CLIENT_SECRET) .when() .post(keycloakURL + "/protocol/openid-connect/token") - .as(AccessTokenResponse.class).getToken(); + .jsonPath().get("access_token"); } } diff --git a/data-index/data-index-service/data-index-service-infinispan/pom.xml b/data-index/data-index-service/data-index-service-infinispan/pom.xml index d9134e9cef..375cdf8cc1 100644 --- a/data-index/data-index-service/data-index-service-infinispan/pom.xml +++ b/data-index/data-index-service/data-index-service-infinispan/pom.xml @@ -101,11 +101,6 @@ kogito-quarkus-test-utils test - - org.keycloak - keycloak-core - test - org.awaitility awaitility diff --git a/data-index/data-index-service/data-index-service-inmemory/pom.xml b/data-index/data-index-service/data-index-service-inmemory/pom.xml index 9b1586fbcd..4dd51a953a 100644 --- a/data-index/data-index-service/data-index-service-inmemory/pom.xml +++ b/data-index/data-index-service/data-index-service-inmemory/pom.xml @@ -89,11 +89,6 @@ kogito-quarkus-test-utils test - - org.keycloak - keycloak-core - test - org.awaitility awaitility diff --git a/data-index/data-index-service/data-index-service-mongodb/pom.xml b/data-index/data-index-service/data-index-service-mongodb/pom.xml index 118314743f..7c2ead3652 100644 --- a/data-index/data-index-service/data-index-service-mongodb/pom.xml +++ b/data-index/data-index-service/data-index-service-mongodb/pom.xml @@ -95,11 +95,6 @@ kogito-quarkus-test-utils test - - org.keycloak - keycloak-core - test - org.awaitility awaitility diff --git a/data-index/data-index-service/data-index-service-postgresql/pom.xml b/data-index/data-index-service/data-index-service-postgresql/pom.xml index 4db0252d0c..43f999c6fa 100644 --- a/data-index/data-index-service/data-index-service-postgresql/pom.xml +++ b/data-index/data-index-service/data-index-service-postgresql/pom.xml @@ -94,11 +94,6 @@ kogito-quarkus-test-utils test - - org.keycloak - keycloak-core - test - org.awaitility awaitility diff --git a/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/model/NodeInstance.java b/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/model/NodeInstance.java index 1e22527c59..ab9df6cadd 100644 --- a/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/model/NodeInstance.java +++ b/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/model/NodeInstance.java @@ -38,6 +38,8 @@ public class NodeInstance { @JsonProperty("leaveTime") private ZonedDateTime exit; + private ZonedDateTime slaDueDate; + @JsonProperty("nodeDefinitionId") private String definitionId; @@ -97,6 +99,14 @@ public void setName(String name) { this.name = name; } + public ZonedDateTime getSlaDueDate() { + return slaDueDate; + } + + public void setSlaDueDate(ZonedDateTime slaDueDate) { + this.slaDueDate = slaDueDate; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -125,6 +135,7 @@ public String toString() { ", type='" + type + '\'' + ", enter=" + enter + ", exit=" + exit + + ", slaDueDate=" + slaDueDate + ", definitionId='" + definitionId + '\'' + '}'; } diff --git a/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/model/ProcessInstanceMeta.java b/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/model/ProcessInstanceMeta.java index d211ea198d..09441ca019 100644 --- a/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/model/ProcessInstanceMeta.java +++ b/data-index/data-index-storage/data-index-storage-api/src/main/java/org/kie/kogito/index/model/ProcessInstanceMeta.java @@ -49,6 +49,7 @@ public class ProcessInstanceMeta { @JsonProperty("updatedBy") private String updatedBy; private ZonedDateTime lastUpdate; + private ZonedDateTime slaDueDate; public String getId() { return id; @@ -186,6 +187,14 @@ public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy; } + public ZonedDateTime getSlaDueDate() { + return slaDueDate; + } + + public void setSlaDueDate(ZonedDateTime slaDueDate) { + this.slaDueDate = slaDueDate; + } + @Override public String toString() { return "ProcessInstanceMeta{" + diff --git a/data-index/data-index-storage/data-index-storage-common/src/main/java/org/kie/kogito/index/storage/merger/ProcessInstanceNodeDataEventMerger.java b/data-index/data-index-storage/data-index-storage-common/src/main/java/org/kie/kogito/index/storage/merger/ProcessInstanceNodeDataEventMerger.java index d800dfd226..bb7c39a5bc 100644 --- a/data-index/data-index-storage/data-index-storage-common/src/main/java/org/kie/kogito/index/storage/merger/ProcessInstanceNodeDataEventMerger.java +++ b/data-index/data-index-storage/data-index-storage-common/src/main/java/org/kie/kogito/index/storage/merger/ProcessInstanceNodeDataEventMerger.java @@ -63,6 +63,7 @@ public ProcessInstance merge(ProcessInstance pi, ProcessInstanceDataEvent dat nodeInstance.setNodeId(body.getNodeDefinitionId()); nodeInstance.setName(body.getNodeName()); nodeInstance.setType(body.getNodeType()); + nodeInstance.setSlaDueDate(toZonedDateTime(body.getSlaDueDate())); ZonedDateTime eventDate = toZonedDateTime(body.getEventDate()); switch (body.getEventType()) { case EVENT_TYPE_ENTER: diff --git a/data-index/data-index-storage/data-index-storage-common/src/main/java/org/kie/kogito/index/storage/merger/ProcessInstanceStateDataEventMerger.java b/data-index/data-index-storage/data-index-storage-common/src/main/java/org/kie/kogito/index/storage/merger/ProcessInstanceStateDataEventMerger.java index b49036fb0c..a7be6d0ea3 100644 --- a/data-index/data-index-storage/data-index-storage-common/src/main/java/org/kie/kogito/index/storage/merger/ProcessInstanceStateDataEventMerger.java +++ b/data-index/data-index-storage/data-index-storage-common/src/main/java/org/kie/kogito/index/storage/merger/ProcessInstanceStateDataEventMerger.java @@ -63,6 +63,7 @@ public ProcessInstance merge(ProcessInstance pi, ProcessInstanceDataEvent dat pi.setLastUpdate(toZonedDateTime(event.getTime())); pi.setDefinition(definitions(event)); pi.setUpdatedBy(event.getData().getEventUser()); + pi.setSlaDueDate(toZonedDateTime(event.getData().getSlaDueDate())); LOGGER.debug("Value after merging: {}", pi); return pi; } diff --git a/data-index/data-index-storage/data-index-storage-infinispan/src/main/java/org/kie/kogito/index/infinispan/protostream/NodeInstanceMarshaller.java b/data-index/data-index-storage/data-index-storage-infinispan/src/main/java/org/kie/kogito/index/infinispan/protostream/NodeInstanceMarshaller.java index 194ad08caa..dd4b5f557c 100644 --- a/data-index/data-index-storage/data-index-storage-infinispan/src/main/java/org/kie/kogito/index/infinispan/protostream/NodeInstanceMarshaller.java +++ b/data-index/data-index-storage/data-index-storage-infinispan/src/main/java/org/kie/kogito/index/infinispan/protostream/NodeInstanceMarshaller.java @@ -42,6 +42,7 @@ public NodeInstance readFrom(ProtoStreamReader reader) throws IOException { node.setExit(dateToZonedDateTime(reader.readDate("exit"))); node.setDefinitionId(reader.readString("definitionId")); node.setNodeId(reader.readString("nodeId")); + node.setSlaDueDate(dateToZonedDateTime(reader.readDate("slaDueDate"))); return node; } @@ -54,6 +55,7 @@ public void writeTo(ProtoStreamWriter writer, NodeInstance node) throws IOExcept writer.writeDate("exit", zonedDateTimeToDate(node.getExit())); writer.writeString("definitionId", node.getDefinitionId()); writer.writeString("nodeId", node.getNodeId()); + writer.writeDate("slaDueDate", zonedDateTimeToDate(node.getSlaDueDate())); } @Override diff --git a/data-index/data-index-storage/data-index-storage-infinispan/src/main/java/org/kie/kogito/index/infinispan/protostream/ProcessInstanceMarshaller.java b/data-index/data-index-storage/data-index-storage-infinispan/src/main/java/org/kie/kogito/index/infinispan/protostream/ProcessInstanceMarshaller.java index ab391703aa..3e46ea2bf3 100644 --- a/data-index/data-index-storage/data-index-storage-infinispan/src/main/java/org/kie/kogito/index/infinispan/protostream/ProcessInstanceMarshaller.java +++ b/data-index/data-index-storage/data-index-storage-infinispan/src/main/java/org/kie/kogito/index/infinispan/protostream/ProcessInstanceMarshaller.java @@ -55,6 +55,7 @@ public class ProcessInstanceMarshaller extends AbstractMarshaller implements Mes protected static final String MILESTONES = "milestones"; protected static final String CREATED_BY = "createdBy"; protected static final String UPDATED_BY = "updatedBy"; + protected static final String SLA_DUE_DATE = "slaDueDate"; public ProcessInstanceMarshaller(ObjectMapper mapper) { super(mapper); @@ -84,6 +85,7 @@ public ProcessInstance readFrom(ProtoStreamReader reader) throws IOException { pi.setVersion(reader.readString(VERSION)); pi.setCreatedBy(reader.readString(CREATED_BY)); pi.setUpdatedBy(reader.readString(UPDATED_BY)); + pi.setSlaDueDate(dateToZonedDateTime(reader.readDate(SLA_DUE_DATE))); return pi; } @@ -110,6 +112,7 @@ public void writeTo(ProtoStreamWriter writer, ProcessInstance pi) throws IOExcep writer.writeString(VERSION, pi.getVersion()); writer.writeString(CREATED_BY, pi.getCreatedBy()); writer.writeString(UPDATED_BY, pi.getCreatedBy()); + writer.writeDate(SLA_DUE_DATE, zonedDateTimeToDate(pi.getSlaDueDate())); } @Override diff --git a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/model/NodeInstanceEntity.java b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/model/NodeInstanceEntity.java index 347e6f9a7f..51c5bef912 100644 --- a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/model/NodeInstanceEntity.java +++ b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/model/NodeInstanceEntity.java @@ -43,6 +43,7 @@ public class NodeInstanceEntity extends AbstractEntity { private String type; private ZonedDateTime enter; private ZonedDateTime exit; + private ZonedDateTime slaDueDate; private String definitionId; @ManyToOne(cascade = CascadeType.ALL, optional = false) @OnDelete(action = OnDeleteAction.CASCADE) @@ -106,6 +107,14 @@ public void setExit(ZonedDateTime exit) { this.exit = exit; } + public ZonedDateTime getSlaDueDate() { + return slaDueDate; + } + + public void setSlaDueDate(ZonedDateTime slaDueDate) { + this.slaDueDate = slaDueDate; + } + public ProcessInstanceEntity getProcessInstance() { return processInstance; } diff --git a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/model/ProcessInstanceEntity.java b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/model/ProcessInstanceEntity.java index 7046de267b..a3a0b0ceb3 100644 --- a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/model/ProcessInstanceEntity.java +++ b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/model/ProcessInstanceEntity.java @@ -68,6 +68,9 @@ public class ProcessInstanceEntity extends AbstractEntity { private String createdBy; private String updatedBy; + + private ZonedDateTime slaDueDate; + @Convert(converter = JsonBinaryConverter.class) @Column(columnDefinition = "jsonb") private ObjectNode variables; @@ -203,6 +206,14 @@ public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy; } + public ZonedDateTime getSlaDueDate() { + return slaDueDate; + } + + public void setSlaDueDate(ZonedDateTime slaDueDate) { + this.slaDueDate = slaDueDate; + } + public ObjectNode getVariables() { return variables; } @@ -286,6 +297,7 @@ public String toString() { ", lastUpdate=" + lastUpdate + ", createdBy=" + createdBy + ", updatedBy=" + updatedBy + + ", slaDueDate=" + slaDueDate + ", variables=" + variables + ", nodes=" + nodes + ", milestones=" + milestones + diff --git a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/ProcessInstanceEntityStorage.java b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/ProcessInstanceEntityStorage.java index 8796f3204a..68e5d24844 100644 --- a/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/ProcessInstanceEntityStorage.java +++ b/data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/ProcessInstanceEntityStorage.java @@ -179,6 +179,7 @@ private NodeInstanceEntity updateNode(NodeInstanceEntity nodeInstance, ProcessIn nodeInstance.setNodeId(body.getNodeDefinitionId()); nodeInstance.setName(body.getNodeName()); nodeInstance.setType(body.getNodeType()); + nodeInstance.setSlaDueDate(toZonedDateTime(body.getSlaDueDate())); ZonedDateTime eventDate = toZonedDateTime(body.getEventDate()); switch (body.getEventType()) { case EVENT_TYPE_ENTER: @@ -219,6 +220,7 @@ private void indexState(ProcessInstanceEntity pi, ProcessInstanceStateEventBody pi.setLastUpdate(toZonedDateTime(data.getEventDate())); pi.setAddons(addons); pi.setEndpoint(endpoint); + pi.setSlaDueDate(toZonedDateTime(data.getSlaDueDate())); } private void indexVariable(ProcessInstanceEntity pi, ProcessInstanceVariableEventBody data) { diff --git a/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/storage/AbstractProcessInstanceStorageIT.java b/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/storage/AbstractProcessInstanceStorageIT.java index b60f7ed300..f8f8c6674e 100644 --- a/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/storage/AbstractProcessInstanceStorageIT.java +++ b/data-index/data-index-storage/data-index-storage-jpa-common/src/test/java/org/kie/kogito/index/jpa/storage/AbstractProcessInstanceStorageIT.java @@ -109,7 +109,7 @@ public void testProcessInstanceNodeEvent() { .hasSize(1); Assertions.assertThat(processInstance.getNodes().get(0)) - .hasNoNullFieldsOrPropertiesExcept("exit") + .hasNoNullFieldsOrPropertiesExcept("exit", "slaDueDate") .hasFieldOrPropertyWithValue("name", "nodeName") .hasFieldOrPropertyWithValue("type", "BoundaryEventNode") .hasFieldOrPropertyWithValue("definitionId", nodeDefinitionId) @@ -125,7 +125,7 @@ public void testProcessInstanceNodeEvent() { .hasSize(1); Assertions.assertThat(processInstance.getNodes().get(0)) - .hasNoNullFieldsOrProperties() + .hasNoNullFieldsOrPropertiesExcept("slaDueDate") .hasFieldOrPropertyWithValue("name", "nodeName") .hasFieldOrPropertyWithValue("type", "BoundaryEventNode") .hasFieldOrPropertyWithValue("definitionId", nodeDefinitionId) diff --git a/data-index/data-index-storage/data-index-storage-jpa/src/main/resources/kie-flyway/db/data-index/ansi/V1.45.0.6__add_sla_due_date_columns.sql b/data-index/data-index-storage/data-index-storage-jpa/src/main/resources/kie-flyway/db/data-index/ansi/V1.45.0.6__add_sla_due_date_columns.sql new file mode 100644 index 0000000000..fdd7838f41 --- /dev/null +++ b/data-index/data-index-storage/data-index-storage-jpa/src/main/resources/kie-flyway/db/data-index/ansi/V1.45.0.6__add_sla_due_date_columns.sql @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +ALTER TABLE processes ADD sla_due_date timestamp; +ALTER TABLE nodes ADD sla_due_date timestamp; \ No newline at end of file diff --git a/data-index/data-index-storage/data-index-storage-mongodb/src/main/java/org/kie/kogito/index/mongodb/model/ProcessInstanceEntity.java b/data-index/data-index-storage/data-index-storage-mongodb/src/main/java/org/kie/kogito/index/mongodb/model/ProcessInstanceEntity.java index 28cef62442..5a66e6f298 100644 --- a/data-index/data-index-storage/data-index-storage-mongodb/src/main/java/org/kie/kogito/index/mongodb/model/ProcessInstanceEntity.java +++ b/data-index/data-index-storage/data-index-storage-mongodb/src/main/java/org/kie/kogito/index/mongodb/model/ProcessInstanceEntity.java @@ -70,6 +70,8 @@ public class ProcessInstanceEntity { String updatedBy; + Long slaDueDate; + public String getId() { return id; } @@ -238,6 +240,14 @@ public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy; } + public Long getSlaDueDate() { + return slaDueDate; + } + + public void setSlaDueDate(Long slaDueDate) { + this.slaDueDate = slaDueDate; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -271,6 +281,8 @@ public static class NodeInstanceEntity { String definitionId; + Long slaDueDate; + public String getId() { return id; } @@ -327,6 +339,14 @@ public void setDefinitionId(String definitionId) { this.definitionId = definitionId; } + public Long getSlaDueDate() { + return slaDueDate; + } + + public void setSlaDueDate(Long slaDueDate) { + this.slaDueDate = slaDueDate; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/data-index/data-index-storage/data-index-storage-mongodb/src/main/java/org/kie/kogito/index/mongodb/model/ProcessInstanceEntityMapper.java b/data-index/data-index-storage/data-index-storage-mongodb/src/main/java/org/kie/kogito/index/mongodb/model/ProcessInstanceEntityMapper.java index 16e1f13d3c..18e674d57e 100644 --- a/data-index/data-index-storage/data-index-storage-mongodb/src/main/java/org/kie/kogito/index/mongodb/model/ProcessInstanceEntityMapper.java +++ b/data-index/data-index-storage/data-index-storage-mongodb/src/main/java/org/kie/kogito/index/mongodb/model/ProcessInstanceEntityMapper.java @@ -77,6 +77,7 @@ public ProcessInstanceEntity mapToEntity(String key, ProcessInstance instance) { entity.setVersion(instance.getVersion()); entity.setCreatedBy(instance.getCreatedBy()); entity.setUpdatedBy(instance.getUpdatedBy()); + entity.setSlaDueDate(zonedDateTimeToInstant(instance.getSlaDueDate())); return entity; } @@ -108,6 +109,7 @@ public ProcessInstance mapToModel(ProcessInstanceEntity entity) { instance.setVersion(entity.getVersion()); instance.setCreatedBy(entity.getCreatedBy()); instance.setUpdatedBy(entity.getCreatedBy()); + instance.setSlaDueDate(instantToZonedDateTime(entity.getSlaDueDate())); return instance; } @@ -146,6 +148,7 @@ NodeInstance toNodeInstance(ProcessInstanceEntity.NodeInstanceEntity entity) { instance.setEnter(instantToZonedDateTime(entity.getEnter())); instance.setExit(instantToZonedDateTime(entity.getExit())); instance.setDefinitionId(entity.getDefinitionId()); + instance.setSlaDueDate(instantToZonedDateTime(entity.getSlaDueDate())); return instance; } @@ -162,6 +165,7 @@ ProcessInstanceEntity.NodeInstanceEntity fromNodeInstance(NodeInstance instance) entity.setEnter(zonedDateTimeToInstant(instance.getEnter())); entity.setExit(zonedDateTimeToInstant(instance.getExit())); entity.setDefinitionId(instance.getDefinitionId()); + entity.setSlaDueDate(zonedDateTimeToInstant(instance.getSlaDueDate())); return entity; } diff --git a/data-index/data-index-storage/data-index-storage-postgresql/src/main/resources/kie-flyway/db/data-index/postgresql/V1.45.0.6__add_sla_due_date_columns.sql b/data-index/data-index-storage/data-index-storage-postgresql/src/main/resources/kie-flyway/db/data-index/postgresql/V1.45.0.6__add_sla_due_date_columns.sql new file mode 100644 index 0000000000..58b83a3266 --- /dev/null +++ b/data-index/data-index-storage/data-index-storage-postgresql/src/main/resources/kie-flyway/db/data-index/postgresql/V1.45.0.6__add_sla_due_date_columns.sql @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +ALTER TABLE IF exists processes ADD COLUMN IF NOT EXISTS sla_due_date timestamp; +ALTER TABLE IF exists nodes ADD COLUMN IF NOT EXISTS sla_due_date timestamp; \ No newline at end of file diff --git a/data-index/data-index-storage/data-index-storage-protobuf/src/main/resources/META-INF/kogito-index.proto b/data-index/data-index-storage/data-index-storage-protobuf/src/main/resources/META-INF/kogito-index.proto index 5c23eecefa..ed6d7c09ee 100644 --- a/data-index/data-index-storage/data-index-storage-protobuf/src/main/resources/META-INF/kogito-index.proto +++ b/data-index/data-index-storage/data-index-storage-protobuf/src/main/resources/META-INF/kogito-index.proto @@ -153,6 +153,7 @@ message ProcessInstance { optional string createdBy = 20; /* @Field(store = Store.YES) */ optional string updatedBy = 21; + optional int64 slaDueDate = 22; } /* @Indexed */ @@ -177,6 +178,7 @@ message NodeInstance { optional string definitionId = 6; /* @Field(store = Store.YES) */ optional string nodeId = 7; + optional int64 slaDueDate = 8; } /* @Indexed */ diff --git a/data-index/kogito-addons-quarkus-data-index-persistence/kogito-addons-quarkus-data-index-persistence-common/runtime/src/main/java/org/kie/kogito/index/addon/api/KogitoAddonRuntimeClientImpl.java b/data-index/kogito-addons-quarkus-data-index-persistence/kogito-addons-quarkus-data-index-persistence-common/runtime/src/main/java/org/kie/kogito/index/addon/api/KogitoAddonRuntimeClientImpl.java index 697dcfd1e0..1f9b64d91d 100644 --- a/data-index/kogito-addons-quarkus-data-index-persistence/kogito-addons-quarkus-data-index-persistence-common/runtime/src/main/java/org/kie/kogito/index/addon/api/KogitoAddonRuntimeClientImpl.java +++ b/data-index/kogito-addons-quarkus-data-index-persistence/kogito-addons-quarkus-data-index-persistence-common/runtime/src/main/java/org/kie/kogito/index/addon/api/KogitoAddonRuntimeClientImpl.java @@ -130,7 +130,8 @@ public CompletableFuture getProcessInstanceDiagram(String serviceURL, Pr if (processSvgService == null) { return CompletableFuture.completedFuture(null); } else { - return CompletableFuture.supplyAsync(() -> processSvgService.getProcessInstanceSvg(processInstance.getProcessId(), processInstance.getId(), null).orElse(null), managedExecutor); + return CompletableFuture.supplyAsync(() -> processSvgService.getProcessInstanceSvg(processInstance.getProcessId(), processInstance.getId(), this.getAuthHeader()).orElse(null), + managedExecutor); } } diff --git a/explainability/explainability-service-rest/pom.xml b/explainability/explainability-service-rest/pom.xml index 6f0e7f1d0f..cb1f027812 100644 --- a/explainability/explainability-service-rest/pom.xml +++ b/explainability/explainability-service-rest/pom.xml @@ -86,11 +86,6 @@ kogito-quarkus-test-utils test - - org.keycloak - keycloak-core - test - diff --git a/explainability/explainability-service-rest/src/test/java/org/kie/kogito/explainability/rest/KeycloakExplainabilityServiceIT.java b/explainability/explainability-service-rest/src/test/java/org/kie/kogito/explainability/rest/KeycloakExplainabilityServiceIT.java index ee532e9153..d014777d8f 100644 --- a/explainability/explainability-service-rest/src/test/java/org/kie/kogito/explainability/rest/KeycloakExplainabilityServiceIT.java +++ b/explainability/explainability-service-rest/src/test/java/org/kie/kogito/explainability/rest/KeycloakExplainabilityServiceIT.java @@ -20,7 +20,6 @@ import org.apache.http.HttpStatus; import org.junit.jupiter.api.Test; -import org.keycloak.representations.AccessTokenResponse; import org.kie.kogito.test.quarkus.QuarkusTestProperty; import org.kie.kogito.testcontainers.KogitoKeycloakContainer; import org.kie.kogito.testcontainers.quarkus.KeycloakQuarkusTestResource; @@ -65,6 +64,6 @@ private String getAccessToken(String userName) { .param("client_secret", KogitoKeycloakContainer.CLIENT_SECRET) .when() .post(keycloakURL + "/protocol/openid-connect/token") - .as(AccessTokenResponse.class).getToken(); + .jsonPath().get("access_token"); } } diff --git a/jitexecutor/jitexecutor-dmn/pom.xml b/jitexecutor/jitexecutor-dmn/pom.xml index f38b164c83..a2e705a419 100644 --- a/jitexecutor/jitexecutor-dmn/pom.xml +++ b/jitexecutor/jitexecutor-dmn/pom.xml @@ -121,6 +121,11 @@ assertj-core test + + org.mockito + mockito-junit-jupiter + test + diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java index 7c73c5eccc..54840c86b8 100644 --- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java +++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java @@ -22,11 +22,15 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; +import org.kie.api.builder.Message; import org.kie.api.io.Resource; import org.kie.dmn.api.core.DMNContext; +import org.kie.dmn.api.core.DMNMessage; import org.kie.dmn.api.core.DMNModel; import org.kie.dmn.api.core.DMNResult; import org.kie.dmn.api.core.DMNRuntime; @@ -51,7 +55,43 @@ public static DMNEvaluator fromXML(String modelXML) { .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new); dmnRuntime.addListener(new JITDMNListener()); DMNModel dmnModel = dmnRuntime.getModels().get(0); - return new DMNEvaluator(dmnModel, dmnRuntime); + return validateForErrors(dmnModel, dmnRuntime); + } + + public static DMNEvaluator fromMultiple(MultipleResourcesPayload payload) { + Map resources = new HashMap<>(); + for (ResourceWithURI r : payload.getResources()) { + Resource readerResource = ResourceFactory.newReaderResource(new StringReader(r.getContent()), "UTF-8"); + readerResource.setSourcePath(r.getURI()); + resources.put(r.getURI(), readerResource); + } + ResolveByKey rbk = new ResolveByKey(resources); + DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults() + .setRelativeImportResolver((x, y, locationURI) -> rbk.readerByKey(locationURI)) + .buildConfiguration() + .fromResources(resources.values()) + .getOrElseThrow(RuntimeException::new); + DMNModel mainModel = null; + for (DMNModel m : dmnRuntime.getModels()) { + if (m.getResource().getSourcePath().equals(payload.getMainURI())) { + mainModel = m; + break; + } + } + if (mainModel == null) { + throw new IllegalStateException("Was not able to identify main model from MultipleResourcesPayload contents."); + } + return validateForErrors(mainModel, dmnRuntime); + } + + static DMNEvaluator validateForErrors(DMNModel dmnModel, DMNRuntime dmnRuntime) { + if (dmnModel.hasErrors()) { + List messages = dmnModel.getMessages(DMNMessage.Severity.ERROR); + String errorMessage = messages.stream().map(Message::getText).collect(Collectors.joining(", ")); + throw new IllegalStateException(errorMessage); + } else { + return new DMNEvaluator(dmnModel, dmnRuntime); + } } private DMNEvaluator(DMNModel dmnModel, DMNRuntime dmnRuntime) { @@ -88,29 +128,4 @@ public JITDMNResult evaluate(Map context) { return new JITDMNResult(getNamespace(), getName(), dmnResult, evaluationHitIds.orElse(Collections.emptyMap())); } - public static DMNEvaluator fromMultiple(MultipleResourcesPayload payload) { - Map resources = new HashMap<>(); - for (ResourceWithURI r : payload.getResources()) { - Resource readerResource = ResourceFactory.newReaderResource(new StringReader(r.getContent()), "UTF-8"); - readerResource.setSourcePath(r.getURI()); - resources.put(r.getURI(), readerResource); - } - ResolveByKey rbk = new ResolveByKey(resources); - DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults() - .setRelativeImportResolver((x, y, locationURI) -> rbk.readerByKey(locationURI)) - .buildConfiguration() - .fromResources(resources.values()) - .getOrElseThrow(RuntimeException::new); - DMNModel mainModel = null; - for (DMNModel m : dmnRuntime.getModels()) { - if (m.getResource().getSourcePath().equals(payload.getMainURI())) { - mainModel = m; - break; - } - } - if (mainModel == null) { - throw new IllegalStateException("Was not able to identify main model from MultipleResourcesPayload contents."); - } - return new DMNEvaluator(mainModel, dmnRuntime); - } } diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/DMNResourceHelper.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/DMNResourceHelper.java new file mode 100644 index 0000000000..b06064acc2 --- /dev/null +++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/DMNResourceHelper.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.kie.kogito.jitexecutor.dmn.api; + +import java.util.function.Supplier; + +import jakarta.ws.rs.core.Response; + +public class DMNResourceHelper { + + private DMNResourceHelper() { + } + + public static Response manageResponse(Supplier responseSupplier) { + try { + return responseSupplier.get(); + } catch (Exception e) { + String errorMessage = e.getMessage() != null ? e.getMessage() : "Failed to get result due to " + e.getClass().getName(); + return Response.status(Response.Status.BAD_REQUEST).entity(errorMessage).build(); + } + } +} diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResource.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResource.java index 69d4eb8b87..19afd5c2e7 100644 --- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResource.java +++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResource.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.function.Supplier; import org.kie.dmn.core.internal.utils.MarshallingStubUtils; import org.kie.kogito.jitexecutor.dmn.JITDMNService; @@ -56,12 +57,15 @@ public Response jitdmn(JITDMNPayload payload) { LOGGER.debug("jitdmn/"); LOGGER.debug(payload.toString()); LOGGER.debug(LINEBREAK); - JITDMNResult evaluateAll = payload.getModel() != null ? jitdmnService.evaluateModel(payload.getModel(), payload.getContext()) : jitdmnService.evaluateModel(payload, payload.getContext()); - Map restResulk = new HashMap<>(); - for (Entry kv : evaluateAll.getContext().getAll().entrySet()) { - restResulk.put(kv.getKey(), MarshallingStubUtils.stubDMNResult(kv.getValue(), String::valueOf)); - } - return Response.ok(restResulk).build(); + Supplier supplier = () -> { + JITDMNResult evaluateAll = payload.getModel() != null ? jitdmnService.evaluateModel(payload.getModel(), payload.getContext()) : jitdmnService.evaluateModel(payload, payload.getContext()); + Map restResulk = new HashMap<>(); + for (Entry kv : evaluateAll.getContext().getAll().entrySet()) { + restResulk.put(kv.getKey(), MarshallingStubUtils.stubDMNResult(kv.getValue(), String::valueOf)); + } + return Response.ok(restResulk).build(); + }; + return DMNResourceHelper.manageResponse(supplier); } @POST @@ -73,8 +77,11 @@ public Response jitdmnResult(JITDMNPayload payload) { LOGGER.debug("jitdmn/dmnresult"); LOGGER.debug(payload.toString()); LOGGER.debug(LINEBREAK); - JITDMNResult dmnResult = payload.getModel() != null ? jitdmnService.evaluateModel(payload.getModel(), payload.getContext()) : jitdmnService.evaluateModel(payload, payload.getContext()); - return Response.ok(dmnResult).build(); + Supplier supplier = () -> { + JITDMNResult dmnResult = payload.getModel() != null ? jitdmnService.evaluateModel(payload.getModel(), payload.getContext()) : jitdmnService.evaluateModel(payload, payload.getContext()); + return Response.ok(dmnResult).build(); + }; + return DMNResourceHelper.manageResponse(supplier); } @POST @@ -86,9 +93,12 @@ public Response jitEvaluateAndExplain(JITDMNPayload payload) { LOGGER.debug("jitdmn/evaluateAndExplain"); LOGGER.debug(payload.toString()); LOGGER.debug(LINEBREAK); - DMNResultWithExplanation response = - payload.getModel() != null ? jitdmnService.evaluateModelAndExplain(payload.getModel(), payload.getContext()) : jitdmnService.evaluateModelAndExplain(payload, payload.getContext()); - return Response.ok(response).build(); + Supplier supplier = () -> { + DMNResultWithExplanation response = + payload.getModel() != null ? jitdmnService.evaluateModelAndExplain(payload.getModel(), payload.getContext()) : jitdmnService.evaluateModelAndExplain(payload, payload.getContext()); + return Response.ok(response).build(); + }; + return DMNResourceHelper.manageResponse(supplier); } } diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/SchemaResource.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/SchemaResource.java index b1ce72029c..674cff40b2 100644 --- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/SchemaResource.java +++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/api/SchemaResource.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import org.eclipse.microprofile.openapi.OASFactory; import org.eclipse.microprofile.openapi.models.OpenAPI; @@ -75,9 +76,12 @@ public Response schema(String payload) { LOGGER.debug("jitdmn/validate"); LOGGER.debug(payload); LOGGER.debug(LINEBREAK); - DMNModel dmnModel = DMNEvaluator.fromXML(payload).getDmnModel(); - DMNOASResult oasResult = DMNOASGeneratorFactory.generator(Collections.singletonList(dmnModel)).build(); - return fullSchema(dmnModel, oasResult, true); + Supplier supplier = () -> { + DMNModel dmnModel = DMNEvaluator.fromXML(payload).getDmnModel(); + DMNOASResult oasResult = DMNOASGeneratorFactory.generator(Collections.singletonList(dmnModel)).build(); + return fullSchema(dmnModel, oasResult, true); + }; + return DMNResourceHelper.manageResponse(supplier); } private Response fullSchema(DMNModel dmnModel, DMNOASResult oasResult, final boolean singleModel) { @@ -111,10 +115,13 @@ private Response fullSchema(DMNModel dmnModel, DMNOASResult oasResult, final boo @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response schema(MultipleResourcesPayload payload) { - DMNEvaluator dmnEvaluator = DMNEvaluator.fromMultiple(payload); - DMNModel dmnModel = dmnEvaluator.getDmnModel(); - DMNOASResult oasResult = DMNOASGeneratorFactory.generator(dmnEvaluator.getAllDMNModels()).build(); - return fullSchema(dmnModel, oasResult, false); + Supplier supplier = () -> { + DMNEvaluator dmnEvaluator = DMNEvaluator.fromMultiple(payload); + DMNModel dmnModel = dmnEvaluator.getDmnModel(); + DMNOASResult oasResult = DMNOASGeneratorFactory.generator(dmnEvaluator.getAllDMNModels()).build(); + return fullSchema(dmnModel, oasResult, false); + }; + return DMNResourceHelper.manageResponse(supplier); } @POST @@ -122,9 +129,12 @@ public Response schema(MultipleResourcesPayload payload) { @Produces(MediaType.APPLICATION_JSON) @Path("form") public Response form(String payload) { - DMNModel dmnModel = DMNEvaluator.fromXML(payload).getDmnModel(); - DMNOASResult oasResult = DMNOASGeneratorFactory.generator(Collections.singletonList(dmnModel)).build(); - return formSchema(dmnModel, oasResult); + Supplier supplier = () -> { + DMNModel dmnModel = DMNEvaluator.fromXML(payload).getDmnModel(); + DMNOASResult oasResult = DMNOASGeneratorFactory.generator(Collections.singletonList(dmnModel)).build(); + return formSchema(dmnModel, oasResult); + }; + return DMNResourceHelper.manageResponse(supplier); } @POST @@ -132,10 +142,13 @@ public Response form(String payload) { @Produces(MediaType.APPLICATION_JSON) @Path("form") public Response form(MultipleResourcesPayload payload) { - DMNEvaluator dmnEvaluator = DMNEvaluator.fromMultiple(payload); - DMNModel dmnModel = dmnEvaluator.getDmnModel(); - DMNOASResult oasResult = DMNOASGeneratorFactory.generator(dmnEvaluator.getAllDMNModels()).build(); - return formSchema(dmnModel, oasResult); + Supplier supplier = () -> { + DMNEvaluator dmnEvaluator = DMNEvaluator.fromMultiple(payload); + DMNModel dmnModel = dmnEvaluator.getDmnModel(); + DMNOASResult oasResult = DMNOASGeneratorFactory.generator(dmnEvaluator.getAllDMNModels()).build(); + return formSchema(dmnModel, oasResult); + }; + return DMNResourceHelper.manageResponse(supplier); } private Response formSchema(DMNModel dmnModel, DMNOASResult oasResult) { diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluatorTest.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluatorTest.java new file mode 100644 index 0000000000..71a5edb1a7 --- /dev/null +++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluatorTest.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.kie.kogito.jitexecutor.dmn; + +import java.io.IOException; +import java.util.Collections; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.kie.dmn.api.core.DMNMessage; +import org.kie.dmn.api.core.DMNModel; +import org.kie.dmn.api.core.DMNRuntime; +import org.kie.dmn.core.impl.DMNRuntimeImpl; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.kie.kogito.jitexecutor.dmn.TestingUtils.getModelFromIoUtils; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class DMNEvaluatorTest { + + private static String model; + private static String invalidModel; + + @BeforeAll + public static void setup() throws IOException { + model = getModelFromIoUtils("invalid_models/DMNv1_x/test.dmn"); + invalidModel = getModelFromIoUtils("invalid_models/DMNv1_5/DMN-Invalid.dmn"); + } + + @Test + void testFromXMLSuccessModel() { + String modelXML = model; + + DMNEvaluator evaluator = DMNEvaluator.fromXML(modelXML); + assertNotNull(evaluator); + } + + @Test + public void testFromXMLModelWithError() { + String modelXML = invalidModel; + + assertThrows(IllegalStateException.class, () -> { + DMNEvaluator.fromXML(modelXML); + }); + } + + @Test + void testValidateForErrorsThrowsException() { + DMNModel dmnModel = mock(DMNModel.class); + DMNRuntime dmnRuntime = mock(DMNRuntime.class); + DMNMessage message = mock(DMNMessage.class); + + String errorMessage = "Error compiling FEEL expression 'Person Age >= 18' for name 'Can Drive?' on node 'Can Drive?': syntax error near 'Age'"; + when(message.getText()).thenReturn(errorMessage); + when(dmnModel.hasErrors()).thenReturn(true); + when(dmnModel.getMessages(DMNMessage.Severity.ERROR)).thenReturn(Collections.singletonList(message)); + + assertThrows(IllegalStateException.class, + () -> DMNEvaluator.validateForErrors(dmnModel, dmnRuntime), errorMessage); + } + + @Test + void testValidateForErrors() { + DMNModel dmnModel = mock(DMNModel.class); + DMNRuntime dmnRuntime = mock(DMNRuntimeImpl.class); + + when(dmnModel.hasErrors()).thenReturn(false); + DMNEvaluator evaluator = DMNEvaluator.validateForErrors(dmnModel, dmnRuntime); + + assertNotNull(evaluator); + } + +} diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/DMNResourceHelperTest.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/DMNResourceHelperTest.java new file mode 100644 index 0000000000..bd6ee56291 --- /dev/null +++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/DMNResourceHelperTest.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.kie.kogito.jitexecutor.dmn; + +import java.util.function.Supplier; + +import org.junit.jupiter.api.Test; +import org.kie.kogito.jitexecutor.dmn.api.DMNResourceHelper; + +import jakarta.ws.rs.core.Response; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class DMNResourceHelperTest { + + @Test + public void testManageResponseWithSuccess() { + Supplier responseSupplier = () -> Response.ok("Success").build(); + try (Response response = DMNResourceHelper.manageResponse(responseSupplier)) { + assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals("Success", response.getEntity()); + } + + } + + @Test + public void testManageResponseWithFailure() { + Supplier responseSupplier = mock(Supplier.class); + when(responseSupplier.get()).thenThrow(new IllegalStateException("Error : Failed to validate")); + try (Response response = DMNResourceHelper.manageResponse(responseSupplier)) { + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertEquals("Error : Failed to validate", response.getEntity()); + } + + } + +} diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/TestingUtils.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/TestingUtils.java index 257b0b4664..f83e0a805a 100644 --- a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/TestingUtils.java +++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/TestingUtils.java @@ -1,4 +1,4 @@ -/** +/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -7,7 +7,7 @@ * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java index cacf238916..99634d4d59 100644 --- a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java +++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java @@ -46,6 +46,7 @@ @QuarkusTest public class JITDMNResourceTest { + private static String model; private static String invalidModel; private static String modelWithExtensionElements; private static String modelWithMultipleEvaluationHitIds; @@ -60,14 +61,15 @@ public class JITDMNResourceTest { @BeforeAll public static void setup() throws IOException { - invalidModel = getModelFromIoUtils("invalid_models/DMNv1_x/test.dmn"); + model = getModelFromIoUtils("invalid_models/DMNv1_x/test.dmn"); + invalidModel = getModelFromIoUtils("invalid_models/DMNv1_5/DMN-Invalid.dmn"); modelWithExtensionElements = getModelFromIoUtils("valid_models/DMNv1_x/testWithExtensionElements.dmn"); modelWithMultipleEvaluationHitIds = getModelFromIoUtils("valid_models/DMNv1_5/MultipleHitRules.dmn"); } @Test void testjitEndpoint() { - JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel, buildContext()); + JITDMNPayload jitdmnpayload = new JITDMNPayload(model, buildContext()); given() .contentType(ContentType.JSON) .body(jitdmnpayload) @@ -116,7 +118,7 @@ void testjitdmnResultEndpointWithEvaluationHitIds() throws JsonProcessingExcepti @Test void testjitExplainabilityEndpoint() { - JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel, buildContext()); + JITDMNPayload jitdmnpayload = new JITDMNPayload(model, buildContext()); given() .contentType(ContentType.JSON) .body(jitdmnpayload) @@ -143,6 +145,42 @@ void testjitdmnWithExtensionElements() { .body(containsString("m"), containsString("n"), containsString("sum")); } + @Test + void testjitEndpointFailure() { + JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel, buildContext()); + given() + .contentType(ContentType.JSON) + .body(jitdmnpayload) + .when().post("/jitdmn") + .then() + .statusCode(400) + .body(containsString("Error compiling FEEL expression 'Person Age >= 18' for name 'Can Drive?' on node 'Can Drive?': syntax error near 'Age'")); + } + + @Test + void testjitdmnEvaluateInvalidModel() { + JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel, buildInvalidModelContext()); + given() + .contentType(ContentType.JSON) + .body(jitdmnpayload) + .when().post("/jitdmn/dmnresult") + .then() + .statusCode(400) + .body(containsString("Error compiling FEEL expression 'Person Age >= 18' for name 'Can Drive?' on node 'Can Drive?': syntax error near 'Age'")); + } + + @Test + void testjitdmnEvaluateAndExplainInvalidModel() { + JITDMNPayload jitdmnpayload = new JITDMNPayload(invalidModel, buildInvalidModelContext()); + given() + .contentType(ContentType.JSON) + .body(jitdmnpayload) + .when().post("/jitdmn/evaluateAndExplain") + .then() + .statusCode(400) + .body(containsString("Error compiling FEEL expression 'Person Age >= 18' for name 'Can Drive?' on node 'Can Drive?': syntax error near 'Age'")); + } + private Map buildContext() { Map context = new HashMap<>(); context.put("FICO Score", 800); @@ -160,4 +198,12 @@ private Map buildMultipleHitContext() { context.put("Numbers", numbers); return context; } + + private Map buildInvalidModelContext() { + Map context = new HashMap<>(); + context.put("Can Drive?", false); + context.put("Person Age", 14); + context.put("Id", 1); + return context; + } } diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/SchemaResourceTest.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/SchemaResourceTest.java index feb28be1c3..6cd22bd460 100644 --- a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/SchemaResourceTest.java +++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/SchemaResourceTest.java @@ -43,4 +43,17 @@ public void test() throws IOException { .statusCode(200) .body(containsString("InputSet"), containsString("x-dmn-type")); } + + @Test + public void testJitDmnValidate() throws IOException { + final String MODEL = getModelFromIoUtils("invalid_models/DMNv1_5/DMN-Invalid.dmn"); + given() + .contentType(ContentType.XML) + .body(MODEL) + .when().post("/jitdmn/schema") + .then() + .statusCode(400) + .body(containsString("Error compiling FEEL expression 'Person Age >= 18' for name 'Can Drive?' on node 'Can Drive?': syntax error near 'Age'")); + + } } diff --git a/jobs-service/jobs-service-common/pom.xml b/jobs-service/jobs-service-common/pom.xml index cdfc82a41a..6b19b74d56 100644 --- a/jobs-service/jobs-service-common/pom.xml +++ b/jobs-service/jobs-service-common/pom.xml @@ -163,11 +163,6 @@ rest-assured test - - org.keycloak - keycloak-core - test - org.mockito mockito-junit-jupiter diff --git a/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/JacksonConfiguration.java b/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/JacksonConfiguration.java index cfbbd024a5..f1603c1ef4 100644 --- a/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/JacksonConfiguration.java +++ b/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/JacksonConfiguration.java @@ -20,7 +20,7 @@ import org.kie.kogito.jobs.DurationExpirationTime; import org.kie.kogito.jobs.ExactExpirationTime; -import org.kie.kogito.jobs.ProcessInstanceJobDescription; +import org.kie.kogito.jobs.JobDescription; import org.kie.kogito.jobs.service.api.serlialization.SerializationUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,8 +46,8 @@ public ObjectMapperCustomizer customizer() { return objectMapper -> { LOGGER.debug("Jackson customization initialized."); SimpleModule kogitoCustomModule = new SimpleModule(); - kogitoCustomModule.addSerializer(ProcessInstanceJobDescription.class, new ProcessInstanceJobDescriptionSerializer()); - kogitoCustomModule.addDeserializer(ProcessInstanceJobDescription.class, new ProcessInstanceJobDescriptionDeserializer()); + kogitoCustomModule.addSerializer(JobDescription.class, new JobDescriptionSerializer()); + kogitoCustomModule.addDeserializer(JobDescription.class, new JobDescriptionDeserializer()); kogitoCustomModule.addSerializer(DurationExpirationTime.class, new DurationExpirationTimeSerializer()); kogitoCustomModule.addDeserializer(DurationExpirationTime.class, new DurationExpirationTimeDeserializer()); kogitoCustomModule.addSerializer(ExactExpirationTime.class, new ExactExpirationTimeSerializer()); diff --git a/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/JobDescriptionDeserializer.java b/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/JobDescriptionDeserializer.java new file mode 100644 index 0000000000..f0a72db2b4 --- /dev/null +++ b/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/JobDescriptionDeserializer.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.kie.kogito.jobs.service.json; + +import java.io.IOException; + +import org.kie.kogito.jobs.ExpirationTime; +import org.kie.kogito.jobs.JobDescription; +import org.kie.kogito.jobs.descriptors.ProcessInstanceJobDescription; +import org.kie.kogito.jobs.descriptors.ProcessInstanceJobDescriptionBuilder; +import org.kie.kogito.jobs.descriptors.UserTaskInstanceJobDescription; +import org.kie.kogito.jobs.descriptors.UserTaskInstanceJobDescriptionBuilder; + +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import static java.util.Optional.ofNullable; + +public class JobDescriptionDeserializer extends StdDeserializer { + + private static final long serialVersionUID = -8307549297456060422L; + + public JobDescriptionDeserializer() { + super(ProcessInstanceJobDescription.class); + } + + @Override + public JobDescription deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JacksonException { + try { + JsonNode node = jp.getCodec().readTree(jp); + String jobDescriptionType = node.get("@type").asText(); + switch (jobDescriptionType) { + case "ProcessInstanceJobDescription": { + ProcessInstanceJobDescriptionBuilder builder = ProcessInstanceJobDescription.newProcessInstanceJobDescriptionBuilder(); + ofNullable(node.get("id")).ifPresent(e -> builder.id(e.textValue())); + ofNullable(node.get("priority")).ifPresent(e -> builder.priority(e.asInt())); + String expirationTimeType = node.get("expirationTime").get("@type").asText(); + builder.expirationTime((ExpirationTime) ctxt.readTreeAsValue(node.get("expirationTime"), Class.forName(expirationTimeType))); + + ofNullable(node.get("timerId")).ifPresent(e -> builder.timerId(e.textValue())); + ofNullable(node.get("processInstanceId")).ifPresent(e -> builder.processInstanceId(e.textValue())); + ofNullable(node.get("rootProcessInstanceId")).ifPresent(e -> builder.rootProcessInstanceId(e.textValue())); + ofNullable(node.get("processId")).ifPresent(e -> builder.processId(e.textValue())); + ofNullable(node.get("rootProcessId")).ifPresent(e -> builder.rootProcessId(e.textValue())); + ofNullable(node.get("nodeInstanceId")).ifPresent(e -> builder.nodeInstanceId(e.textValue())); + + return builder.build(); + } + case "UserTaskInstanceJobDescription": { + UserTaskInstanceJobDescriptionBuilder builder = UserTaskInstanceJobDescription.newUserTaskInstanceJobDescriptionBuilder(); + ofNullable(node.get("id")).ifPresent(e -> builder.id(e.textValue())); + ofNullable(node.get("priority")).ifPresent(e -> builder.priority(e.asInt())); + String expirationTimeType = node.get("expirationTime").get("@type").asText(); + builder.expirationTime((ExpirationTime) ctxt.readTreeAsValue(node.get("expirationTime"), Class.forName(expirationTimeType))); + + ofNullable(node.get("userTaskInstanceId")).ifPresent(e -> builder.userTaskInstanceId(e.textValue())); + return builder.build(); + } + } + } catch (ClassNotFoundException e1) { + throw new IllegalArgumentException("expiration time class not found", e1); + } + return null; + } + +} diff --git a/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/ProcessInstanceJobDescriptionSerializer.java b/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/JobDescriptionSerializer.java similarity index 50% rename from jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/ProcessInstanceJobDescriptionSerializer.java rename to jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/JobDescriptionSerializer.java index 379da2a0e5..22935e0e37 100644 --- a/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/ProcessInstanceJobDescriptionSerializer.java +++ b/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/JobDescriptionSerializer.java @@ -20,32 +20,40 @@ import java.io.IOException; -import org.kie.kogito.jobs.ProcessInstanceJobDescription; +import org.kie.kogito.jobs.JobDescription; +import org.kie.kogito.jobs.descriptors.ProcessInstanceJobDescription; +import org.kie.kogito.jobs.descriptors.UserTaskInstanceJobDescription; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; -public class ProcessInstanceJobDescriptionSerializer extends StdSerializer { +public class JobDescriptionSerializer extends StdSerializer { private static final long serialVersionUID = -8307549297456060422L; - public ProcessInstanceJobDescriptionSerializer() { - super(ProcessInstanceJobDescription.class); + public JobDescriptionSerializer() { + super(JobDescription.class); } @Override - public void serialize(ProcessInstanceJobDescription value, JsonGenerator jgen, SerializerProvider provider) throws IOException { + public void serialize(JobDescription value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeStartObject(); + jgen.writeStringField("@type", value.getClass().getSimpleName()); jgen.writeStringField("id", value.id()); - jgen.writeStringField("timerId", value.timerId()); - jgen.writeObjectField("expirationTime", value.expirationTime()); jgen.writeNumberField("priority", value.priority()); - jgen.writeStringField("processInstanceId", value.processInstanceId()); - jgen.writeStringField("rootProcessInstanceId", value.rootProcessInstanceId()); - jgen.writeStringField("processId", value.processId()); - jgen.writeStringField("rootProcessId", value.rootProcessId()); - jgen.writeStringField("nodeInstanceId", value.nodeInstanceId()); + jgen.writeObjectField("expirationTime", value.expirationTime()); + if (value instanceof ProcessInstanceJobDescription jobDescription) { + jgen.writeStringField("timerId", jobDescription.timerId()); + jgen.writeStringField("processInstanceId", jobDescription.processInstanceId()); + jgen.writeStringField("rootProcessInstanceId", jobDescription.rootProcessInstanceId()); + jgen.writeStringField("processId", jobDescription.processId()); + jgen.writeStringField("rootProcessId", jobDescription.rootProcessId()); + jgen.writeStringField("nodeInstanceId", jobDescription.nodeInstanceId()); + jgen.writeEndObject(); + } else if (value instanceof UserTaskInstanceJobDescription userTaskInstanceJobDescription) { + jgen.writeStringField("userTaskInstanceId", userTaskInstanceJobDescription.getUserTaskInstanceId()); + } jgen.writeEndObject(); } diff --git a/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/ProcessInstanceJobDescriptionDeserializer.java b/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/ProcessInstanceJobDescriptionDeserializer.java deleted file mode 100644 index 6ccfb99f47..0000000000 --- a/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/json/ProcessInstanceJobDescriptionDeserializer.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.kie.kogito.jobs.service.json; - -import java.io.IOException; - -import org.kie.kogito.jobs.ExpirationTime; -import org.kie.kogito.jobs.ProcessInstanceJobDescription; -import org.kie.kogito.jobs.ProcessInstanceJobDescriptionBuilder; - -import com.fasterxml.jackson.core.JacksonException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; - -import static java.util.Optional.ofNullable; - -public class ProcessInstanceJobDescriptionDeserializer extends StdDeserializer { - - private static final long serialVersionUID = -8307549297456060422L; - - public ProcessInstanceJobDescriptionDeserializer() { - super(ProcessInstanceJobDescription.class); - } - - @Override - public ProcessInstanceJobDescription deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JacksonException { - ProcessInstanceJobDescriptionBuilder builder = ProcessInstanceJobDescription.builder(); - - JsonNode node = jp.getCodec().readTree(jp); - ofNullable(node.get("id")).ifPresent(e -> builder.id(e.textValue())); - ofNullable(node.get("timerId")).ifPresent(e -> builder.timerId(e.textValue())); - ofNullable(node.get("priority")).ifPresent(e -> builder.priority(e.asInt())); - ofNullable(node.get("processInstanceId")).ifPresent(e -> builder.processInstanceId(e.textValue())); - ofNullable(node.get("rootProcessInstanceId")).ifPresent(e -> builder.rootProcessInstanceId(e.textValue())); - ofNullable(node.get("processId")).ifPresent(e -> builder.processId(e.textValue())); - ofNullable(node.get("rootProcessId")).ifPresent(e -> builder.rootProcessId(e.textValue())); - ofNullable(node.get("nodeInstanceId")).ifPresent(e -> builder.nodeInstanceId(e.textValue())); - - String type = node.get("expirationTime").get("@type").asText(); - try { - builder.expirationTime((ExpirationTime) ctxt.readTreeAsValue(node.get("expirationTime"), Class.forName(type))); - } catch (ClassNotFoundException | IOException e1) { - e1.printStackTrace(); - } - - return builder.build(); - } - -} diff --git a/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/stream/AbstractJobStreams.java b/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/stream/AbstractJobStreams.java index 64189e2ab1..d09d3bbc5f 100644 --- a/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/stream/AbstractJobStreams.java +++ b/jobs-service/jobs-service-common/src/main/java/org/kie/kogito/jobs/service/stream/AbstractJobStreams.java @@ -65,16 +65,12 @@ public boolean isEnabled() { public void jobStatusChange(JobDetails job) { if (isEnabled()) { try { - JobDataEvent event = JobDataEvent - .builder() - .source(url + RestApiConstants.JOBS_PATH) - .data(ScheduledJobAdapter.of(job))//this should support jobs crated with V1 and V2 - .build(); + JobDataEvent event = buildEvent(job); LOGGER.debug("emit jobStatusChange, hasRequests: {}, eventId: {}, jobDetails: {}", emitter.hasRequests(), event.getId(), job); String json = objectMapper.writeValueAsString(event); emitter.send(decorate(ContextAwareMessage.of(json) .withAck(() -> onAck(event.getId(), job)) - .withNack(reason -> onNack(reason, job)))); + .withNack(reason -> onNack(reason, job)), event)); } catch (Exception e) { String msg = String.format("An unexpected error was produced while processing a Job status change for the job: %s", job); LOGGER.error(msg, e); @@ -82,6 +78,14 @@ public void jobStatusChange(JobDetails job) { } } + protected JobDataEvent buildEvent(JobDetails job) { + return JobDataEvent + .builder() + .source(url + RestApiConstants.JOBS_PATH) + .data(ScheduledJobAdapter.of(job))//this should support jobs crated with V1 and V2 + .build(); + } + protected CompletionStage onAck(String eventId, JobDetails job) { LOGGER.debug("Job Status change emitted successfully, eventId: {}, jobDetails: {}", eventId, job); return CompletableFuture.completedFuture(null); @@ -93,7 +97,7 @@ protected CompletionStage onNack(Throwable reason, JobDetails job) { return CompletableFuture.completedFuture(null); } - protected Message decorate(Message message) { + protected Message decorate(Message message, JobDataEvent event) { return message; } } diff --git a/jobs-service/jobs-service-common/src/test/java/org/kie/kogito/jobs/service/resource/BaseKeycloakJobServiceTest.java b/jobs-service/jobs-service-common/src/test/java/org/kie/kogito/jobs/service/resource/BaseKeycloakJobServiceTest.java index 617efe207c..1a2d56764e 100644 --- a/jobs-service/jobs-service-common/src/test/java/org/kie/kogito/jobs/service/resource/BaseKeycloakJobServiceTest.java +++ b/jobs-service/jobs-service-common/src/test/java/org/kie/kogito/jobs/service/resource/BaseKeycloakJobServiceTest.java @@ -24,7 +24,6 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.keycloak.representations.AccessTokenResponse; import org.kie.kogito.jobs.api.Job; import org.kie.kogito.jobs.api.JobBuilder; import org.kie.kogito.jobs.service.model.JobStatus; @@ -234,6 +233,6 @@ private String getAccessToken(String userName) { .param("client_secret", KogitoKeycloakContainer.CLIENT_SECRET) .when() .post(keycloakURL + "/protocol/openid-connect/token") - .as(AccessTokenResponse.class).getToken(); + .jsonPath().get("access_token"); } } diff --git a/jobs-service/jobs-service-common/src/test/java/org/kie/kogito/jobs/service/stream/AbstractJobStreamsTest.java b/jobs-service/jobs-service-common/src/test/java/org/kie/kogito/jobs/service/stream/AbstractJobStreamsTest.java index f7ac6ed1ce..1f2e3fc33b 100644 --- a/jobs-service/jobs-service-common/src/test/java/org/kie/kogito/jobs/service/stream/AbstractJobStreamsTest.java +++ b/jobs-service/jobs-service-common/src/test/java/org/kie/kogito/jobs/service/stream/AbstractJobStreamsTest.java @@ -58,7 +58,7 @@ public abstract class AbstractJobStreamsTest { protected static final String URL = "http://localhost:8180"; private static final String SERIALIZED_MESSAGE = "SERIALIZED_MESSAGE"; - private static final String JOB_ID = "JOB_ID"; + protected static final String JOB_ID = "JOB_ID"; private static final String CORRELATION_ID = "CORRELATION_ID"; private static final JobStatus STATUS = JobStatus.SCHEDULED; private static final ZonedDateTime LAST_UPDATE = ZonedDateTime.parse("2022-08-03T18:00:15.001+01:00"); @@ -170,7 +170,7 @@ private JobDetails mockJobDetails() { } - private void assertExpectedEvent(JobDataEvent event) { + protected void assertExpectedEvent(JobDataEvent event) { assertThat(event.getId()).isNotNull(); assertThat(event.getType()).isEqualTo(JobDataEvent.JOB_EVENT_TYPE); assertThat(event.getSource()).hasToString(URL + "/jobs"); diff --git a/jobs-service/jobs-service-infinispan/pom.xml b/jobs-service/jobs-service-infinispan/pom.xml index a5bfaed242..df8231b831 100644 --- a/jobs-service/jobs-service-infinispan/pom.xml +++ b/jobs-service/jobs-service-infinispan/pom.xml @@ -114,11 +114,6 @@ rest-assured test - - org.keycloak - keycloak-core - test - com.github.tomakehurst wiremock-jre8 diff --git a/jobs-service/jobs-service-inmemory/pom.xml b/jobs-service/jobs-service-inmemory/pom.xml index 70d047a98b..8ab200e963 100644 --- a/jobs-service/jobs-service-inmemory/pom.xml +++ b/jobs-service/jobs-service-inmemory/pom.xml @@ -107,11 +107,6 @@ rest-assured test - - org.keycloak - keycloak-core - test - com.github.tomakehurst wiremock-jre8 diff --git a/jobs-service/jobs-service-messaging-http/src/main/java/org/kie/kogito/jobs/service/messaging/http/stream/HttpJobStreams.java b/jobs-service/jobs-service-messaging-http/src/main/java/org/kie/kogito/jobs/service/messaging/http/stream/HttpJobStreams.java index 52bb50d35f..61a2efebaf 100644 --- a/jobs-service/jobs-service-messaging-http/src/main/java/org/kie/kogito/jobs/service/messaging/http/stream/HttpJobStreams.java +++ b/jobs-service/jobs-service-messaging-http/src/main/java/org/kie/kogito/jobs/service/messaging/http/stream/HttpJobStreams.java @@ -26,6 +26,7 @@ import org.eclipse.microprofile.reactive.messaging.Emitter; import org.eclipse.microprofile.reactive.messaging.Message; import org.eclipse.microprofile.reactive.messaging.OnOverflow; +import org.kie.kogito.jobs.service.events.JobDataEvent; import org.kie.kogito.jobs.service.model.JobDetails; import org.kie.kogito.jobs.service.stream.AbstractJobStreams; import org.slf4j.Logger; @@ -45,6 +46,7 @@ public class HttpJobStreams extends AbstractJobStreams { public static final String PUBLISH_EVENTS_CONFIG_KEY = "kogito.jobs-service.http.job-status-change-events"; public static final String JOB_STATUS_CHANGE_EVENTS_HTTP = "kogito-job-service-job-status-events-http"; + public static final String PARTITION_KEY_EXTENSION = "partitionkey"; private static final Logger LOGGER = LoggerFactory.getLogger(HttpJobStreams.class); @@ -70,7 +72,16 @@ public void jobStatusChange(JobDetails job) { } @Override - protected Message decorate(Message message) { + protected JobDataEvent buildEvent(JobDetails job) { + JobDataEvent event = super.buildEvent(job); + // use the well-known extension https://github.com/cloudevents/spec/blob/main/cloudevents/extensions/partitioning.md + // to instruct potential http driven Brokers like, Knative Eventing Kafka Broker, to process accordingly. + event.addExtensionAttribute(PARTITION_KEY_EXTENSION, event.getData().getId()); + return event; + } + + @Override + protected Message decorate(Message message, JobDataEvent event) { return message.addMetadata(OUTGOING_HTTP_METADATA.get()); } } diff --git a/jobs-service/jobs-service-messaging-http/src/test/java/org/kie/kogito/jobs/service/messaging/http/stream/HttpJobStreamsTest.java b/jobs-service/jobs-service-messaging-http/src/test/java/org/kie/kogito/jobs/service/messaging/http/stream/HttpJobStreamsTest.java index 8449d88da6..7b951b5e39 100644 --- a/jobs-service/jobs-service-messaging-http/src/test/java/org/kie/kogito/jobs/service/messaging/http/stream/HttpJobStreamsTest.java +++ b/jobs-service/jobs-service-messaging-http/src/test/java/org/kie/kogito/jobs/service/messaging/http/stream/HttpJobStreamsTest.java @@ -21,6 +21,7 @@ import java.util.Optional; import org.eclipse.microprofile.reactive.messaging.Message; +import org.kie.kogito.jobs.service.events.JobDataEvent; import org.kie.kogito.jobs.service.stream.AbstractJobStreamsTest; import io.cloudevents.jackson.JsonFormat; @@ -29,6 +30,7 @@ import jakarta.ws.rs.core.HttpHeaders; import static org.assertj.core.api.Assertions.assertThat; +import static org.kie.kogito.jobs.service.messaging.http.stream.HttpJobStreams.PARTITION_KEY_EXTENSION; class HttpJobStreamsTest extends AbstractJobStreamsTest { @@ -44,4 +46,12 @@ protected void assertExpectedMetadata(Message message) { assertThat(metadata.getHeaders()).hasSize(1); assertThat(metadata.getHeaders().get(HttpHeaders.CONTENT_TYPE)).containsExactlyInAnyOrder(JsonFormat.CONTENT_TYPE); } + + @Override + protected void assertExpectedEvent(JobDataEvent event) { + super.assertExpectedEvent(event); + assertThat(event.getExtension(PARTITION_KEY_EXTENSION)) + .isNotNull() + .isEqualTo(JOB_ID); + } } diff --git a/jobs-service/jobs-service-messaging-kafka/src/main/java/org/kie/kogito/jobs/service/messaging/kafka/stream/KafkaJobStreams.java b/jobs-service/jobs-service-messaging-kafka/src/main/java/org/kie/kogito/jobs/service/messaging/kafka/stream/KafkaJobStreams.java index c9b149ede2..315d89dff4 100644 --- a/jobs-service/jobs-service-messaging-kafka/src/main/java/org/kie/kogito/jobs/service/messaging/kafka/stream/KafkaJobStreams.java +++ b/jobs-service/jobs-service-messaging-kafka/src/main/java/org/kie/kogito/jobs/service/messaging/kafka/stream/KafkaJobStreams.java @@ -23,7 +23,9 @@ import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.reactive.messaging.Channel; import org.eclipse.microprofile.reactive.messaging.Emitter; +import org.eclipse.microprofile.reactive.messaging.Message; import org.eclipse.microprofile.reactive.messaging.OnOverflow; +import org.kie.kogito.jobs.service.events.JobDataEvent; import org.kie.kogito.jobs.service.model.JobDetails; import org.kie.kogito.jobs.service.stream.AbstractJobStreams; import org.kie.kogito.jobs.service.stream.AvailableStreams; @@ -32,6 +34,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; +import io.smallrye.reactive.messaging.kafka.api.OutgoingKafkaRecordMetadata; + import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -54,4 +58,10 @@ public void jobStatusChange(JobDetails job) { LOGGER.debug("jobStatusChange call received, enabled: {}, job: {}", enabled, job); super.jobStatusChange(job); } + + @Override + protected Message decorate(Message message, JobDataEvent event) { + // regular kafka partitioning. + return message.addMetadata(OutgoingKafkaRecordMetadata.builder().withKey(event.getData().getId()).build()); + } } diff --git a/jobs-service/jobs-service-messaging-kafka/src/test/java/org/kie/kogito/jobs/service/messaging/kafka/stream/KafkaJobStreamsTest.java b/jobs-service/jobs-service-messaging-kafka/src/test/java/org/kie/kogito/jobs/service/messaging/kafka/stream/KafkaJobStreamsTest.java index a0dbc6c95d..d5be8d1f5f 100644 --- a/jobs-service/jobs-service-messaging-kafka/src/test/java/org/kie/kogito/jobs/service/messaging/kafka/stream/KafkaJobStreamsTest.java +++ b/jobs-service/jobs-service-messaging-kafka/src/test/java/org/kie/kogito/jobs/service/messaging/kafka/stream/KafkaJobStreamsTest.java @@ -20,12 +20,24 @@ import java.util.Optional; +import org.eclipse.microprofile.reactive.messaging.Message; import org.kie.kogito.jobs.service.stream.AbstractJobStreamsTest; +import io.smallrye.reactive.messaging.kafka.api.OutgoingKafkaRecordMetadata; + +import static org.assertj.core.api.Assertions.assertThat; + class KafkaJobStreamsTest extends AbstractJobStreamsTest { @Override protected KafkaJobStreams createJobStreams() { return new KafkaJobStreams(objectMapper, Optional.of(true), emitter, URL); } + + @Override + protected void assertExpectedMetadata(Message message) { + OutgoingKafkaRecordMetadata metadata = message.getMetadata(OutgoingKafkaRecordMetadata.class).orElse(null); + assertThat(metadata).isNotNull(); + assertThat(metadata.getKey()).isEqualTo(JOB_ID); + } } diff --git a/jobs-service/jobs-service-mongodb/pom.xml b/jobs-service/jobs-service-mongodb/pom.xml index 3830fcb196..45018a9d47 100644 --- a/jobs-service/jobs-service-mongodb/pom.xml +++ b/jobs-service/jobs-service-mongodb/pom.xml @@ -101,11 +101,6 @@ rest-assured test - - org.keycloak - keycloak-core - test - com.github.tomakehurst wiremock-jre8 diff --git a/jobs-service/jobs-service-postgresql-common/pom.xml b/jobs-service/jobs-service-postgresql-common/pom.xml index ab5b3eac63..a88b981d04 100644 --- a/jobs-service/jobs-service-postgresql-common/pom.xml +++ b/jobs-service/jobs-service-postgresql-common/pom.xml @@ -99,11 +99,6 @@ rest-assured test - - org.keycloak - keycloak-core - test - com.github.tomakehurst wiremock-jre8 diff --git a/jobs-service/jobs-service-storage-jpa/pom.xml b/jobs-service/jobs-service-storage-jpa/pom.xml index b49d36ce73..99de150744 100644 --- a/jobs-service/jobs-service-storage-jpa/pom.xml +++ b/jobs-service/jobs-service-storage-jpa/pom.xml @@ -113,11 +113,6 @@ rest-assured test - - org.keycloak - keycloak-core - test - com.github.tomakehurst wiremock-jre8 diff --git a/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/EmbeddedJobExecutor.java b/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/EmbeddedJobExecutor.java index ead3bbf2a2..961e0485aa 100644 --- a/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/EmbeddedJobExecutor.java +++ b/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/EmbeddedJobExecutor.java @@ -19,9 +19,13 @@ package org.kie.kogito.jobs.embedded; import java.util.Optional; +import java.util.function.Supplier; import org.kie.kogito.Application; import org.kie.kogito.Model; +import org.kie.kogito.jobs.JobDescription; +import org.kie.kogito.jobs.descriptors.ProcessInstanceJobDescription; +import org.kie.kogito.jobs.descriptors.UserTaskInstanceJobDescription; import org.kie.kogito.jobs.service.api.Recipient; import org.kie.kogito.jobs.service.exception.JobExecutionException; import org.kie.kogito.jobs.service.executor.JobExecutor; @@ -31,40 +35,81 @@ import org.kie.kogito.process.Process; import org.kie.kogito.process.Processes; import org.kie.kogito.services.jobs.impl.TriggerJobCommand; +import org.kie.kogito.usertask.UserTaskInstance; +import org.kie.kogito.usertask.UserTasks; import io.smallrye.mutiny.Uni; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Alternative; +import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; +import static org.kie.kogito.services.uow.UnitOfWorkExecutor.executeInUnitOfWork; + @ApplicationScoped @Alternative public class EmbeddedJobExecutor implements JobExecutor { @Inject - Processes processes; + Instance processes; + + @Inject + Instance userTasks; @Inject Application application; @Override public Uni execute(JobDetails jobDetails) { - - String correlationId = jobDetails.getCorrelationId(); RecipientInstance recipientModel = (RecipientInstance) jobDetails.getRecipient(); InVMRecipient recipient = (InVMRecipient) recipientModel.getRecipient(); - String timerId = recipient.getPayload().getData().timerId(); - String processInstanceId = recipient.getPayload().getData().processInstanceId(); - Optional> process; - try { - process = processes.processByProcessInstanceId(processInstanceId); - } catch (Exception ex) { - return Uni.createFrom().failure( - new JobExecutionException(jobDetails.getId(), - "Unexpected error when executing Embedded request for job: " + jobDetails.getId() + ". " + ex.getMessage(), - ex)); + JobDescription jobDescription = recipient.getPayload().getData(); + if (jobDescription instanceof ProcessInstanceJobDescription processInstanceJobDescription && processes.isResolvable()) { + return processJobDescription(jobDetails, processInstanceJobDescription); + } else if (jobDescription instanceof UserTaskInstanceJobDescription userTaskInstanceJobDescription && userTasks.isResolvable()) { + return processJobDescription(jobDetails, userTaskInstanceJobDescription); } + + return Uni.createFrom().item( + JobExecutionResponse.builder() + .code("401") + .jobId(jobDetails.getId()) + .now() + .message("job cannot be processed") + .build()); + } + + private Uni processJobDescription(JobDetails jobDetails, UserTaskInstanceJobDescription userTaskInstanceJobDescription) { + Supplier execute = () -> executeInUnitOfWork(application.unitOfWorkManager(), () -> { + Optional userTaskInstance = userTasks.get().instances().findById(userTaskInstanceJobDescription.getUserTaskInstanceId()); + if (userTaskInstance.isEmpty()) { + return null; + } + UserTaskInstance instance = userTaskInstance.get(); + instance.trigger(userTaskInstanceJobDescription); + return null; + }); + + return Uni.createFrom().item(execute) + .onFailure() + .transform( + unexpected -> new JobExecutionException(jobDetails.getId(), "Unexpected error when executing Embedded request for job: " + jobDetails.getId() + ". " + unexpected.getMessage(), + unexpected)) + .onItem() + .transform(res -> JobExecutionResponse.builder() + .message("Embedded job executed") + .code(String.valueOf(200)) + .now() + .jobId(jobDetails.getId()) + .build()); + + } + + private Uni processJobDescription(JobDetails jobDetails, ProcessInstanceJobDescription processInstanceJobDescription) { + String timerId = processInstanceJobDescription.timerId(); + String processInstanceId = processInstanceJobDescription.processInstanceId(); + Optional> process = processes.get().processByProcessInstanceId(processInstanceId); if (process.isEmpty()) { return Uni.createFrom().item( JobExecutionResponse.builder() @@ -77,9 +122,13 @@ public Uni execute(JobDetails jobDetails) { Integer limit = jobDetails.getRetries(); - TriggerJobCommand command = new TriggerJobCommand(processInstanceId, correlationId, timerId, limit, process.get(), application.unitOfWorkManager()); + Supplier execute = () -> executeInUnitOfWork(application.unitOfWorkManager(), () -> { + TriggerJobCommand command = new TriggerJobCommand(processInstanceId, jobDetails.getCorrelationId(), timerId, limit, process.get(), application.unitOfWorkManager()); + return command.execute(); + }); - return Uni.createFrom().item(command::execute) + return Uni.createFrom() + .item(execute) .onFailure() .transform( unexpected -> new JobExecutionException(jobDetails.getId(), "Unexpected error when executing Embedded request for job: " + jobDetails.getId() + ". " + unexpected.getMessage(), diff --git a/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/EmbeddedJobsService.java b/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/EmbeddedJobsService.java index 95b9b0d92e..84754c6dc2 100644 --- a/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/EmbeddedJobsService.java +++ b/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/EmbeddedJobsService.java @@ -20,9 +20,8 @@ import java.util.concurrent.ExecutionException; +import org.kie.kogito.jobs.JobDescription; import org.kie.kogito.jobs.JobsService; -import org.kie.kogito.jobs.ProcessInstanceJobDescription; -import org.kie.kogito.jobs.ProcessJobDescription; import org.kie.kogito.jobs.api.JobCallbackResourceDef; import org.kie.kogito.jobs.service.adapter.JobDetailsAdapter; import org.kie.kogito.jobs.service.api.Job; @@ -54,13 +53,7 @@ public EmbeddedJobsService() { } @Override - public String scheduleProcessJob(ProcessJobDescription description) { - LOGGER.debug("ScheduleProcessJob: {} not supported", description); - return null; - } - - @Override - public String scheduleProcessInstanceJob(ProcessInstanceJobDescription description) { + public String scheduleJob(JobDescription description) { try { Job job = Job.builder() .id(description.id()) diff --git a/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/InVMPayloadData.java b/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/InVMPayloadData.java index cb49a135b6..3a9cdf9286 100644 --- a/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/InVMPayloadData.java +++ b/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/InVMPayloadData.java @@ -18,31 +18,31 @@ */ package org.kie.kogito.jobs.embedded; -import org.kie.kogito.jobs.ProcessInstanceJobDescription; +import org.kie.kogito.jobs.JobDescription; import org.kie.kogito.jobs.service.api.PayloadData; -public class InVMPayloadData extends PayloadData { +public class InVMPayloadData extends PayloadData { - private ProcessInstanceJobDescription jobDescription; + private JobDescription jobDescription; public InVMPayloadData() { // do nothing } - public void setJobDescription(ProcessInstanceJobDescription jobDescription) { + public void setJobDescription(JobDescription jobDescription) { this.jobDescription = jobDescription; } - public ProcessInstanceJobDescription getJobDescription() { + public JobDescription getJobDescription() { return jobDescription; } @Override - public ProcessInstanceJobDescription getData() { + public JobDescription getData() { return jobDescription; } - public InVMPayloadData(ProcessInstanceJobDescription data) { + public InVMPayloadData(JobDescription data) { this.jobDescription = data; } diff --git a/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/JobInVMEventPublisher.java b/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/JobInVMEventPublisher.java index dae4ac4ecf..78434dc841 100644 --- a/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/JobInVMEventPublisher.java +++ b/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/main/java/org/kie/kogito/jobs/embedded/JobInVMEventPublisher.java @@ -25,7 +25,8 @@ import org.eclipse.microprofile.config.inject.ConfigProperty; import org.kie.kogito.event.EventPublisher; import org.kie.kogito.event.job.JobInstanceDataEvent; -import org.kie.kogito.jobs.ProcessInstanceJobDescription; +import org.kie.kogito.jobs.JobDescription; +import org.kie.kogito.jobs.descriptors.ProcessInstanceJobDescription; import org.kie.kogito.jobs.service.adapter.ScheduledJobAdapter; import org.kie.kogito.jobs.service.api.Recipient; import org.kie.kogito.jobs.service.model.JobDetails; @@ -93,13 +94,15 @@ public void observe(@ObservesAsync EmbeddedJobServiceEvent serviceEvent) { try { ScheduledJob scheduledJob = ScheduledJobAdapter.of(jobDetails); Recipient recipient = jobDetails.getRecipient().getRecipient(); - ProcessInstanceJobDescription jobDescription = recipient.getPayload().getJobDescription(); - - scheduledJob.setProcessInstanceId(jobDescription.processInstanceId()); - scheduledJob.setProcessId(jobDescription.processId()); - scheduledJob.setRootProcessInstanceId(jobDescription.rootProcessInstanceId()); - scheduledJob.setRootProcessId(jobDescription.rootProcessId()); - scheduledJob.setNodeInstanceId(jobDescription.nodeInstanceId()); + JobDescription jobDescription = recipient.getPayload().getJobDescription(); + + if (jobDescription instanceof ProcessInstanceJobDescription processInstanceJobDescription) { + scheduledJob.setProcessInstanceId(processInstanceJobDescription.processInstanceId()); + scheduledJob.setProcessId(processInstanceJobDescription.processId()); + scheduledJob.setRootProcessInstanceId(processInstanceJobDescription.rootProcessInstanceId()); + scheduledJob.setRootProcessId(processInstanceJobDescription.rootProcessId()); + scheduledJob.setNodeInstanceId(processInstanceJobDescription.nodeInstanceId()); + } byte[] jsonContent = objectMapper.writeValueAsBytes(scheduledJob); JobInstanceDataEvent event = new JobInstanceDataEvent(JOB_EVENT_TYPE, diff --git a/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/test/java/org/kie/kogito/jobs/embedded/EmbeddedJobsServiceTest.java b/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/test/java/org/kie/kogito/jobs/embedded/EmbeddedJobsServiceTest.java index c854f86f7f..33e0c8be4b 100644 --- a/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/test/java/org/kie/kogito/jobs/embedded/EmbeddedJobsServiceTest.java +++ b/jobs-service/kogito-addons-jobs-service/kogito-addons-quarkus-jobs/src/test/java/org/kie/kogito/jobs/embedded/EmbeddedJobsServiceTest.java @@ -28,7 +28,7 @@ import org.kie.kogito.event.job.JobInstanceDataEvent; import org.kie.kogito.jobs.DurationExpirationTime; import org.kie.kogito.jobs.JobsService; -import org.kie.kogito.jobs.ProcessInstanceJobDescription; +import org.kie.kogito.jobs.descriptors.ProcessInstanceJobDescription; import io.quarkus.test.junit.QuarkusTest; @@ -58,7 +58,7 @@ public void testJobService() throws Exception { CountDownLatch latch = new CountDownLatch(8); publisher.setLatch(latch); - ProcessInstanceJobDescription description = ProcessInstanceJobDescription.builder() + ProcessInstanceJobDescription description = ProcessInstanceJobDescription.newProcessInstanceJobDescriptionBuilder() .generateId() .timerId("-1") .expirationTime(DurationExpirationTime.now()) @@ -68,9 +68,9 @@ public void testJobService() throws Exception { .rootProcessId(null) .nodeInstanceId(NODE_INSTANCE_ID) .build(); - jobService.scheduleProcessInstanceJob(description); + jobService.scheduleJob(description); - ProcessInstanceJobDescription descriptionWRootProcess = ProcessInstanceJobDescription.builder() + ProcessInstanceJobDescription descriptionWRootProcess = ProcessInstanceJobDescription.newProcessInstanceJobDescriptionBuilder() .generateId() .timerId("-1") .expirationTime(DurationExpirationTime.now()) @@ -80,7 +80,7 @@ public void testJobService() throws Exception { .rootProcessId(ROOT_PROCESS_ID) .nodeInstanceId(NODE_INSTANCE_ID) .build(); - jobService.scheduleProcessInstanceJob(descriptionWRootProcess); + jobService.scheduleJob(descriptionWRootProcess); latch.await(); diff --git a/pom.xml b/pom.xml index 554fc18758..0b560abd24 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,6 @@ 2024-01-16T00:00:00Z - 3.4.1 @@ -99,9 +98,10 @@ org.apache.maven.plugins maven-artifact-plugin - ${version.maven.artifact.plugin} ${project.build.outputTimestamp} + + image-build.zip @@ -131,10 +131,20 @@ explainability trusty jitexecutor - apps-integration-tests + + allSubmodules + + + !only.reproducible + + + + apps-integration-tests + + optaplanner-downstream diff --git a/security-commons/pom.xml b/security-commons/pom.xml index 4e1705ec57..a26cb5abd4 100644 --- a/security-commons/pom.xml +++ b/security-commons/pom.xml @@ -53,11 +53,6 @@ kogito-quarkus-test-utils test - - org.keycloak - keycloak-core - test - io.quarkus quarkus-junit5 diff --git a/security-commons/src/test/java/org/kie/kogito/security/KeycloakSecurityCommonsServiceIT.java b/security-commons/src/test/java/org/kie/kogito/security/KeycloakSecurityCommonsServiceIT.java index a013593b8c..9e238e7fed 100644 --- a/security-commons/src/test/java/org/kie/kogito/security/KeycloakSecurityCommonsServiceIT.java +++ b/security-commons/src/test/java/org/kie/kogito/security/KeycloakSecurityCommonsServiceIT.java @@ -19,7 +19,6 @@ package org.kie.kogito.security; import org.junit.jupiter.api.Test; -import org.keycloak.representations.AccessTokenResponse; import org.kie.kogito.test.quarkus.QuarkusTestProperty; import org.kie.kogito.testcontainers.KogitoKeycloakContainer; import org.kie.kogito.testcontainers.quarkus.KeycloakQuarkusTestResource; @@ -74,6 +73,6 @@ private String getAccessToken(String userName) { .param("client_secret", KogitoKeycloakContainer.CLIENT_SECRET) .when() .post(keycloakURL + "/protocol/openid-connect/token") - .as(AccessTokenResponse.class).getToken(); + .jsonPath().get("access_token"); } } diff --git a/trusty/trusty-service/trusty-service-common/pom.xml b/trusty/trusty-service/trusty-service-common/pom.xml index f58205a872..8c53ec2e92 100644 --- a/trusty/trusty-service/trusty-service-common/pom.xml +++ b/trusty/trusty-service/trusty-service-common/pom.xml @@ -124,11 +124,6 @@ awaitility test - - org.keycloak - keycloak-core - test - org.skyscreamer jsonassert diff --git a/trusty/trusty-service/trusty-service-common/src/test/java/org/kie/kogito/trusty/service/common/KeycloakTrustyServiceIT.java b/trusty/trusty-service/trusty-service-common/src/test/java/org/kie/kogito/trusty/service/common/KeycloakTrustyServiceIT.java index c860f37841..6fb21ddff6 100644 --- a/trusty/trusty-service/trusty-service-common/src/test/java/org/kie/kogito/trusty/service/common/KeycloakTrustyServiceIT.java +++ b/trusty/trusty-service/trusty-service-common/src/test/java/org/kie/kogito/trusty/service/common/KeycloakTrustyServiceIT.java @@ -24,7 +24,6 @@ import org.apache.http.HttpStatus; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; -import org.keycloak.representations.AccessTokenResponse; import org.kie.kogito.test.quarkus.QuarkusTestProperty; import org.kie.kogito.testcontainers.KogitoKeycloakContainer; import org.kie.kogito.testcontainers.quarkus.KeycloakQuarkusTestResource; @@ -77,6 +76,6 @@ private String getAccessToken(String userName) { .param("client_secret", KogitoKeycloakContainer.CLIENT_SECRET) .when() .post(keycloakURL + "/protocol/openid-connect/token") - .as(AccessTokenResponse.class).getToken(); + .jsonPath().get("access_token"); } }