From 082122f4473fb8b39a1147d19d70c1a3237ed5d8 Mon Sep 17 00:00:00 2001 From: renczesstefan Date: Fri, 5 Sep 2025 12:23:57 +0200 Subject: [PATCH 1/2] [NAE-2199] Force delete of processes - Introduced the ability to forcefully delete cases, tasks, and PetriNets, bypassing event-driven actions through a new `force` parameter. - Updated `WorkflowService`, `TaskService`, and `PetriNetService` to support forced deletion logic. - Modified controller endpoints to allow optional forcing of deletions via request parameters. - Updated relevant service interfaces to include new method overloads for forced deletion. - Improved code readability by introducing logging enhancements with structured placeholders. This change provides greater flexibility for scenarios with strict deletion requirements, ensuring optional event handling during deletions. --- .../petrinet/service/PetriNetService.java | 14 +++++--- .../service/interfaces/IPetriNetService.java | 9 +++++ .../petrinet/web/PetriNetController.java | 4 +-- .../engine/workflow/service/TaskService.java | 18 ++++++++-- .../workflow/service/WorkflowService.java | 36 ++++++++++++++----- .../service/interfaces/ITaskService.java | 4 +++ .../service/interfaces/IWorkflowService.java | 6 ++++ 7 files changed, 73 insertions(+), 18 deletions(-) diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java index f9dad57a49..d65be6631f 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java @@ -524,19 +524,25 @@ private void addValueCriteria(Query query, Query queryTotal, Criteria criteria) @Override @Transactional public void deletePetriNet(String processId, LoggedUser loggedUser) { + deletePetriNet(processId, loggedUser, false); + } + + @Override + @Transactional + public void deletePetriNet(String processId, LoggedUser loggedUser, boolean force) { Optional petriNetOptional = repository.findById(processId); - if (!petriNetOptional.isPresent()) { + if (petriNetOptional.isEmpty()) { throw new IllegalArgumentException("Could not find process with id [" + processId + "]"); } PetriNet petriNet = petriNetOptional.get(); - log.info("[" + processId + "]: Initiating deletion of Petri net " + petriNet.getIdentifier() + " version " + petriNet.getVersion().toString()); + log.info("[{}]: Initiating deletion of Petri net {} version {}", processId, petriNet.getIdentifier(), petriNet.getVersion().toString()); userService.removeRoleOfDeletedPetriNet(petriNet, null); - workflowService.deleteInstancesOfPetriNet(petriNet); + workflowService.deleteInstancesOfPetriNet(petriNet, force); processRoleService.deleteRolesOfNet(petriNet, loggedUser); - log.info("[" + processId + "]: User [" + userService.getLoggedOrSystem().getStringId() + "] is deleting Petri net " + petriNet.getIdentifier() + " version " + petriNet.getVersion().toString()); + log.info("[{}]: User [{}] is deleting Petri net {} version {}", processId, userService.getLoggedOrSystem().getStringId(), petriNet.getIdentifier(), petriNet.getVersion().toString()); publisher.publishEvent(new ProcessDeleteEvent(petriNet, EventPhase.PRE)); repository.deleteBy_id(petriNet.getObjectId()); evictCache(petriNet); diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java index 73921f1e2f..9bd338b60b 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java @@ -311,6 +311,15 @@ static DataFieldReference transformToReference(PetriNet net, Transition transiti */ void deletePetriNet(String id, LoggedUser loggedUser); + /** + * Deletes a PetriNet by its ID. + * + * @param id the ID of the PetriNet to delete + * @param loggedUser the user requesting the deletion + * @param force whether to force the deletion without running events + */ + void deletePetriNet(String id, LoggedUser loggedUser, boolean force); + /** * Runs the specified set of actions on a PetriNet. * diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/PetriNetController.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/PetriNetController.java index 2cc3e4edff..eb9cb4f90f 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/PetriNetController.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/PetriNetController.java @@ -223,14 +223,14 @@ PagedModel searchElasticPetriNets(@RequestBody PetriN @ApiResponse(responseCode = "403", description = "Caller doesn't fulfill the authorisation requirements") }) @DeleteMapping(value = "/{id}", produces = MediaTypes.HAL_JSON_VALUE) - public MessageResource deletePetriNet(@PathVariable("id") String processId, Authentication auth) { + public MessageResource deletePetriNet(@PathVariable("id") String processId, @RequestParam(required = false) boolean force, Authentication auth) { String decodedProcessId = decodeUrl(processId); if (Objects.equals(decodedProcessId, "")) { log.error("Deleting Petri net [" + processId + "] failed: could not decode process ID from URL"); return MessageResource.errorMessage("Deleting Petri net " + processId + " failed!"); } LoggedUser user = (LoggedUser) auth.getPrincipal(); - asyncRunner.execute(() -> this.service.deletePetriNet(decodedProcessId, user)); + asyncRunner.execute(() -> this.service.deletePetriNet(decodedProcessId, user, force)); return MessageResource.successMessage("Petri net " + decodedProcessId + " is being deleted"); } diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java index e8ee3f5b93..ac21c61ae5 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java @@ -924,15 +924,27 @@ public void delete(List tasks, Case useCase) { @Override public void delete(List tasks, String caseId) { - workflowService.removeTasksFromCase(tasks, caseId); - log.info("[" + caseId + "]: Tasks of case are being deleted"); + delete(tasks, caseId, false); + } + + @Override + public void delete(List tasks, String caseId, boolean force) { + if (!force) { + workflowService.removeTasksFromCase(tasks, caseId); + } + log.info("[{}]: Tasks of case are being deleted", caseId); taskRepository.deleteAll(tasks); tasks.forEach(t -> elasticTaskService.remove(t.getStringId())); } @Override public void deleteTasksByCase(String caseId) { - delete(taskRepository.findAllByCaseId(caseId), caseId); + deleteTasksByCase(caseId, false); + } + + @Override + public void deleteTasksByCase(String caseId, boolean force) { + delete(taskRepository.findAllByCaseId(caseId), caseId, force); } @Override 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 08b0760728..f1bf9a0e30 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 @@ -392,33 +392,51 @@ public DeleteCaseEventOutcome deleteCase(String caseId) { @Override public DeleteCaseEventOutcome deleteCase(Case useCase, Map params) { + return deleteCase(useCase, params, false); + } - DeleteCaseEventOutcome outcome = new DeleteCaseEventOutcome(useCase, eventService.runActions(useCase.getPetriNet().getPreDeleteActions(), useCase, Optional.empty(), params)); - publisher.publishEvent(new DeleteCaseEvent(outcome, EventPhase.PRE)); - useCase = ((Evaluator) evaluationService.getEvaluator("default")).apply(new DeleteCaseEvent(outcome, EventPhase.PRE));; + @Override + public DeleteCaseEventOutcome deleteCase(Case useCase, Map params, boolean force) { + DeleteCaseEventOutcome outcome = null; + if (!force) { + outcome = new DeleteCaseEventOutcome(useCase, eventService.runActions(useCase.getPetriNet().getPreDeleteActions(), useCase, Optional.empty(), params)); + publisher.publishEvent(new DeleteCaseEvent(outcome, EventPhase.PRE)); + useCase = ((Evaluator) evaluationService.getEvaluator("default")).apply(new DeleteCaseEvent(outcome, EventPhase.PRE)); + } log.info("[" + useCase.getStringId() + "]: User [" + userService.getLoggedOrSystem().getStringId() + "] is deleting case " + useCase.getTitle()); taskService.deleteTasksByCase(useCase.getStringId()); repository.delete(useCase); - - outcome.addOutcomes(eventService.runActions(useCase.getPetriNet().getPostDeleteActions(), null, Optional.empty(), params)); - addMessageToOutcome(useCase.getPetriNet(), CaseEventType.DELETE, outcome); - ((Evaluator) evaluationService.getEvaluator("noContext")).apply(new DeleteCaseEvent(outcome, EventPhase.POST)); - publisher.publishEvent(new DeleteCaseEvent(outcome, EventPhase.POST)); + if (!force) { + outcome.addOutcomes(eventService.runActions(useCase.getPetriNet().getPostDeleteActions(), null, Optional.empty(), params)); + addMessageToOutcome(useCase.getPetriNet(), CaseEventType.DELETE, outcome); + ((Evaluator) evaluationService.getEvaluator("noContext")).apply(new DeleteCaseEvent(outcome, EventPhase.POST)); + publisher.publishEvent(new DeleteCaseEvent(outcome, EventPhase.POST)); + } return outcome; } @Override public DeleteCaseEventOutcome deleteCase(Case useCase) { + return deleteCase(useCase, false); + } + + @Override + public DeleteCaseEventOutcome deleteCase(Case useCase, boolean force) { return deleteCase(useCase, new HashMap<>()); } @Override public void deleteInstancesOfPetriNet(PetriNet net) { + deleteInstancesOfPetriNet(net, false); + } + + @Override + public void deleteInstancesOfPetriNet(PetriNet net, boolean force) { log.info("[" + net.getStringId() + "]: User " + userService.getLoggedOrSystem().getStringId() + " is deleting all cases and tasks of Petri net " + net.getIdentifier() + " version " + net.getVersion().toString()); List cases = this.searchAll(QCase.case$.petriNetObjectId.eq(net.getObjectId())).getContent(); if (!cases.isEmpty()) { - cases.forEach(this::deleteCase); + cases.forEach(aCase -> deleteCase(aCase, new HashMap<>(), force)); } } diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/ITaskService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/ITaskService.java index 724ae44ac4..e8bf1f73ed 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/ITaskService.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/ITaskService.java @@ -112,8 +112,12 @@ public interface ITaskService { void delete(List tasks, String caseId); + void delete(List tasks, String caseId, boolean force); + void deleteTasksByCase(String caseId); + void deleteTasksByCase(String caseId, boolean force); + void deleteTasksByPetriNetId(String petriNetId); List findAllByCase(String caseId, Locale locale); 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 aca8f7b720..2f3726b6dd 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 @@ -55,10 +55,16 @@ public interface IWorkflowService { DeleteCaseEventOutcome deleteCase(Case useCase, Map params); + DeleteCaseEventOutcome deleteCase(Case useCase, Map params, boolean force); + DeleteCaseEventOutcome deleteCase(Case useCase); + DeleteCaseEventOutcome deleteCase(Case useCase, boolean force); + void deleteInstancesOfPetriNet(PetriNet net); + void deleteInstancesOfPetriNet(PetriNet net, boolean force); + void updateMarking(Case useCase); Page searchAll(Predicate predicate); From 4565c2b9068f434eae645cb62332e1bfebee51d3 Mon Sep 17 00:00:00 2001 From: Milan Mladoniczky <6153201+tuplle@users.noreply.github.com> Date: Fri, 5 Sep 2025 22:15:31 +0200 Subject: [PATCH 2/2] [NAE-2199] Force delete of processes - Updated deleteCase method to include force parameter in overloaded versions. --- .../application/engine/workflow/service/WorkflowService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 f1bf9a0e30..1f551ede85 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 @@ -418,12 +418,12 @@ public DeleteCaseEventOutcome deleteCase(Case useCase, Map param @Override public DeleteCaseEventOutcome deleteCase(Case useCase) { - return deleteCase(useCase, false); + return deleteCase(useCase, false); } @Override public DeleteCaseEventOutcome deleteCase(Case useCase, boolean force) { - return deleteCase(useCase, new HashMap<>()); + return deleteCase(useCase, new HashMap<>(), force); } @Override