diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java index 4967e85e3ce..be243a76b8d 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java @@ -111,7 +111,7 @@ public GetDataEventOutcome getData(String taskId, Map params) { } @Override - public SetDataEventOutcome setData(String taskId, Map> dataSet, Map params) throws JsonProcessingException { + public SetDataEventOutcome setData(String taskId, Map> dataSet, Map params) throws JsonProcessingException { log.debug("Setting data for task [{}] with params: [{}]", taskId, params == null ? "null" : params.toString()); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(dataSet); diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/EventService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/EventService.java index e7c8549c214..14eba051496 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/EventService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/EventService.java @@ -51,6 +51,9 @@ public List runActions(List actions, Case useCase, Optiona List functions = useCase == null ? Collections.emptyList() : useCase.getPetriNet().getFunctions(); actions.forEach(action -> { List outcomes = actionsRunner.run(action, useCase, task, params, functions); + if (useCase != null) { + workflowService.updateCaseFromDb(useCase); + } outcomes.stream().filter(SetDataEventOutcome.class::isInstance) .forEach(outcome -> { if (((SetDataEventOutcome) outcome).getChangedFields().isEmpty()) return; @@ -75,6 +78,9 @@ public List runEventActions(Case useCase, Task task, List List functions = useCase == null ? Collections.emptyList() : useCase.getPetriNet().getFunctions(); actions.forEach(action -> { List outcomes = actionsRunner.run(action, useCase, taskOpt, params, functions); + if (useCase != null) { + workflowService.updateCaseFromDb(useCase); + } outcomes.stream().filter(SetDataEventOutcome.class::isInstance) .forEach(outcome -> { if (((SetDataEventOutcome) outcome).getChangedFields().isEmpty()) return; diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java index a16077f5307..1a25eb15fb0 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java @@ -252,6 +252,16 @@ public Case resolveActorRef(Case useCase, boolean canSaveUseCase) { return useCase; } + @Override + public void updateCaseFromDb(Case useCase) { + Case actual = findOne(useCase.getStringId()); + actual.getDataSet().forEach((id, dataField) -> { + if (dataField.isNewerThen(useCase.getDataField(id))) { + useCase.getDataSet().put(id, dataField); + } + }); + } + /** * Resolves actor permissions for the useCase based on the actor list data field. * diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java index 0065281b897..48818587fa9 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java @@ -31,6 +31,8 @@ public interface IWorkflowService { Case resolveActorRef(Case useCase, boolean canSaveUseCase); + void updateCaseFromDb(Case useCase); + CreateCaseEventOutcome createCase(CreateCaseParams createCaseParams); Page findAllByAuthor(String authorId, String petriNet, Pageable pageable); diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/utils/Nullable.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/utils/Nullable.java index df50295a4ab..6326d09ee42 100644 --- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/utils/Nullable.java +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/utils/Nullable.java @@ -25,9 +25,12 @@ public final class Nullable implements Serializable { private static final long serialVersionUID = 8683452581122892189L; private final T value; + + private final Class type; - private Nullable(T value) { + private Nullable(T value, Class type) { this.value = value; + this.type = type; } /** @@ -39,6 +42,15 @@ public T get() { return value; } + /** + * Returns the runtime class type of the value that can be held by this {@code Nullable} instance. + * + * @return the {@code Class} object representing the type {@code T}, or {@code null} if no type was specified + */ + public Class getType() { + return type; + } + /** * Creates a new {@code Nullable} instance containing the given value. * @@ -46,7 +58,19 @@ public T get() { * @return a {@code Nullable} instance wrapping the provided value */ public static Nullable of(T value) { - return new Nullable<>(value); + return new Nullable<>(value, null); + } + + /** + * Creates a new {@code Nullable} instance containing the given value and explicit type information. + * + * @param the type of the value to wrap + * @param value the value to wrap in a {@code Nullable} instance, can be {@code null} + * @param type the {@code Class} object representing the type {@code T}, can be {@code null} + * @return a {@code Nullable} instance wrapping the provided value with type information + */ + public static Nullable of(T value, Class type) { + return new Nullable<>(value, type); } /** @@ -56,7 +80,18 @@ public static Nullable of(T value) { * @return an empty {@code Nullable} instance */ public static Nullable empty() { - return new Nullable<>(null); + return new Nullable<>(null, null); + } + + /** + * Returns an empty {@code Nullable} instance holding no value but with explicit type information. + * + * @param the type of the value that can be held by this {@code Nullable} instance + * @param type the {@code Class} object representing the type {@code T}, can be {@code null} + * @return an empty {@code Nullable} instance with type information + */ + public static Nullable empty(Class type) { + return new Nullable<>(null, type); } /** @@ -125,7 +160,7 @@ public Nullable filter(Predicate predicate) { if (isEmpty()) { return this; } else { - return predicate.test(value) ? this : empty(); + return predicate.test(value) ? this : empty(type); } } @@ -276,7 +311,8 @@ public boolean equals(Object obj) { } return obj instanceof Nullable other - && Objects.equals(value, other.value); + && Objects.equals(value, other.value) + && Objects.equals(type, other.type); } /** @@ -287,7 +323,7 @@ public boolean equals(Object obj) { */ @Override public int hashCode() { - return Objects.hashCode(value); + return Objects.hash(value, type); } /** diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java index 0fcf7a37301..fac2f567093 100644 --- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java +++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java @@ -47,7 +47,7 @@ public interface ActionApi { * @return the outcome of the set data operation * @throws JsonProcessingException if there is an error processing JSON data */ - SetDataEventOutcome setData(String taskId, Map> dataSet, Map params) throws JsonProcessingException; + SetDataEventOutcome setData(String taskId, Map> dataSet, Map params) throws JsonProcessingException; /** * Finds a specific case by its ID.