From c91d26e85af07b7955d5b3cab7ca6dc1be7393f1 Mon Sep 17 00:00:00 2001 From: Enrique Gonzalez Martinez Date: Mon, 2 Sep 2024 15:01:38 +0200 Subject: [PATCH] fix UserTaskIT --- .../org/kie/kogito/auth/SecurityPolicy.java | 17 +- .../process/workitem/KogitoWorkItem.java | 4 + .../org/kie/kogito/usertask/UserTask.java | 2 +- .../kie/kogito/usertask/UserTaskInstance.java | 5 + .../kogito/usertask/model/UserTaskModel.java | 10 +- .../UserTaskStateEventDataEventAdapter.java | 4 +- .../org/jbpm/bpmn2/xml/UserTaskHandler.java | 15 +- .../instance/node/WorkItemNodeInstance.java | 2 +- .../UserTaskKogitoWorkItemHandler.java | 130 +++- .../kogito/usertask/impl/DefaultUserTask.java | 6 +- .../impl/DefaultUserTaskInstance.java | 19 + .../impl/model/DefaultHumanTaskLifeCycle.java | 118 --- .../workitems/InternalKogitoWorkItem.java | 2 + .../workitems/impl/KogitoWorkItemImpl.java | 15 + .../api/template/TemplatedGenerator.java | 7 +- .../kie/kogito/codegen/AbstractCodegenIT.java | 9 + .../codegen/tests/CallActivityTaskIT.java | 13 +- .../kie/kogito/codegen/tests/UserTaskIT.java | 699 ++++++++++-------- .../codegen/usertask/UserTaskCodegen.java | 13 +- 19 files changed, 638 insertions(+), 452 deletions(-) delete mode 100644 jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/model/DefaultHumanTaskLifeCycle.java diff --git a/api/kogito-api/src/main/java/org/kie/kogito/auth/SecurityPolicy.java b/api/kogito-api/src/main/java/org/kie/kogito/auth/SecurityPolicy.java index f9e7d3a6797..8d56e994953 100644 --- a/api/kogito-api/src/main/java/org/kie/kogito/auth/SecurityPolicy.java +++ b/api/kogito-api/src/main/java/org/kie/kogito/auth/SecurityPolicy.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Objects; @@ -62,15 +61,21 @@ protected SecurityPolicy(IdentityProvider identity) { @Override public void enforce(KogitoWorkItem workItem) { - String actualOwner = (String) workItem.getParameter("ActorId"); + String actualOwners = (String) workItem.getParameter("ActorId"); String actualRoles = (String) workItem.getParameter("GroupId"); - if (actualOwner != null || actualRoles != null) { - List owners = actualOwner != null ? List.of(actualOwner.split(",")) : Collections.emptyList(); - List roles = actualRoles != null ? List.of(actualRoles.split(",")) : Collections.emptyList(); + String excludedOwner = (String) workItem.getParameter("ExcludedOwnerId"); + if (actualOwners != null || actualRoles != null) { + List owners = actualOwners != null ? new ArrayList<>(List.of(actualOwners.split(","))) : new ArrayList<>(); + List excluded = excludedOwner != null ? new ArrayList<>(List.of(excludedOwner.split(","))) : new ArrayList<>(); + owners.removeAll(excluded); + List roles = actualRoles != null ? List.of(actualRoles.split(",")) : new ArrayList<>(); List userRoles = new ArrayList<>(identity.getRoles()); userRoles.retainAll(roles); - if (!owners.contains(identity.getName()) && userRoles.isEmpty()) { + String actualOwner = workItem.getActualOwner(); + if (actualOwner != null && !identity.getName().equals(actualOwner)) { throw new NotAuthorizedException("this work item " + workItem.getStringId() + " is not allows by this owner" + actualOwner); + } else if (!owners.contains(identity.getName()) && userRoles.isEmpty()) { + throw new NotAuthorizedException("this work item " + workItem.getStringId() + " is not allows by this owner" + actualOwners + " or " + actualRoles); } } } diff --git a/api/kogito-api/src/main/java/org/kie/kogito/internal/process/workitem/KogitoWorkItem.java b/api/kogito-api/src/main/java/org/kie/kogito/internal/process/workitem/KogitoWorkItem.java index ab13cbb65bd..262b0b0bd79 100644 --- a/api/kogito-api/src/main/java/org/kie/kogito/internal/process/workitem/KogitoWorkItem.java +++ b/api/kogito-api/src/main/java/org/kie/kogito/internal/process/workitem/KogitoWorkItem.java @@ -33,6 +33,8 @@ public interface KogitoWorkItem extends WorkItem { String getExternalReferenceId(); + String getActualOwner(); + String getStringId(); /** @@ -87,6 +89,8 @@ public interface KogitoWorkItem extends WorkItem { */ KogitoProcessInstance getProcessInstance(); + void removeOutput(String name); + void setOutput(String name, Object value); default void setOutputs(Map outputs) { diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTask.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTask.java index 99db80bec9e..2cf98b446c5 100644 --- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTask.java +++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTask.java @@ -62,7 +62,7 @@ public interface UserTask { * * @return task priority if present */ - String getTaskPriority(); + Integer getTaskPriority(); /** * Returns reference name of the task diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskInstance.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskInstance.java index d46bbb458a2..df63c216e29 100644 --- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskInstance.java +++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskInstance.java @@ -33,6 +33,10 @@ public interface UserTaskInstance { String status(); + boolean hasActualOwner(); + + void setActuaOwner(String string); + String getActualOwner(); UserTaskTransitionToken createTransitionToken(String transitionId, Map data); @@ -42,4 +46,5 @@ public interface UserTaskInstance { void complete(); void abort(); + } diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/UserTaskModel.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/UserTaskModel.java index 518f3fce8db..3c96e326597 100644 --- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/UserTaskModel.java +++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/UserTaskModel.java @@ -26,7 +26,7 @@ public class UserTaskModel { private String taskName; private String taskDescription; - private String taskPriority; + private Integer taskPriority; private Set potentialUsers; private Set potentialGroups; private Set adminUsers; @@ -86,11 +86,11 @@ public void setTaskDescription(String taskDescription) { * * @return task priority if present */ - public String getTaskPriority() { + public Integer getTaskPriority() { return this.taskPriority; } - public void setTaskPriority(String taskPriority) { + public void setTaskPriority(Integer taskPriority) { this.taskPriority = taskPriority; } @@ -142,6 +142,10 @@ public Set getAdminGroups() { return this.adminGroups; } + public void setAdminGroups(Set adminGroups) { + this.adminGroups = adminGroups; + } + /** * Returns excluded users that cannot work on this task * diff --git a/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/adapter/UserTaskStateEventDataEventAdapter.java b/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/adapter/UserTaskStateEventDataEventAdapter.java index c267898f5f1..d405078ad55 100644 --- a/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/adapter/UserTaskStateEventDataEventAdapter.java +++ b/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/adapter/UserTaskStateEventDataEventAdapter.java @@ -42,6 +42,8 @@ public boolean accept(Object payload) { public DataEvent adapt(Object payload) { UserTaskStateEvent event = (UserTaskStateEvent) payload; Map metadata = AdapterHelper.buildUserTaskMetadata(event.getUserTaskInstance()); + Integer priority = event.getUserTaskModel().getTaskPriority(); + String priorityStr = priority != null ? priority.toString() : null; UserTaskInstanceStateEventBody.Builder builder = UserTaskInstanceStateEventBody.create() .eventDate(new Date()) @@ -50,7 +52,7 @@ public DataEvent adapt(Object payload) { .userTaskInstanceId(event.getUserTaskInstance().id()) .userTaskName(event.getUserTaskModel().getTaskName()) .userTaskDescription(event.getUserTaskModel().getTaskDescription()) - .userTaskPriority(event.getUserTaskModel().getTaskPriority()) + .userTaskPriority(priorityStr) .userTaskReferenceName(event.getUserTask().getReferenceName()) .state(event.getNewStatus()) .actualOwner(event.getUserTaskInstance().getActualOwner()) diff --git a/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/UserTaskHandler.java b/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/UserTaskHandler.java index e59037960fc..7c72fe878f2 100644 --- a/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/UserTaskHandler.java +++ b/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/UserTaskHandler.java @@ -43,7 +43,20 @@ public Class generateNodeFor() { } private static final Set taskParameters = Set.of( - "NotStartedNotify", "NotCompletedNotify", "NotCompletedReassign", "NotStartedReassign", "Description", "Comment", "ActorId", "GroupId", "Priority", "Skippable", "Content"); + "NotStartedNotify", + "NotCompletedNotify", + "NotCompletedReassign", + "NotStartedReassign", + "Description", + "Comment", + "ActorId", + "GroupId", + "Priority", + "Skippable", + "Content", + "ExcludedOwnerId", + "BusinessAdministratorId", + "BusinessAdministratorGroupId"); @Override protected Node handleNode(final Node node, final Element element, final String uri, diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/WorkItemNodeInstance.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/WorkItemNodeInstance.java index 65ffd85311d..5eadbbb50f0 100755 --- a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/WorkItemNodeInstance.java +++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/WorkItemNodeInstance.java @@ -162,7 +162,7 @@ public void internalTrigger(final KogitoNodeInstance from, String type) { Map parameters = workItemNode.getWork().getWorkParametersFactory().apply(workItem); parameters.forEach(workItem::setParameter); } - + processWorkItemHandler(() -> ((InternalKogitoWorkItemManager) InternalProcessRuntime.asKogitoProcessRuntime(getProcessInstance().getKnowledgeRuntime()).getKogitoWorkItemManager()) .internalExecuteWorkItem(workItem)); if (!workItemNode.isWaitForCompletion()) { diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/jbpm/usertask/handler/UserTaskKogitoWorkItemHandler.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/jbpm/usertask/handler/UserTaskKogitoWorkItemHandler.java index 81d26e3d2b1..564a5643464 100644 --- a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/jbpm/usertask/handler/UserTaskKogitoWorkItemHandler.java +++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/jbpm/usertask/handler/UserTaskKogitoWorkItemHandler.java @@ -18,27 +18,63 @@ */ package org.kie.kogito.jbpm.usertask.handler; +import java.util.Map; import java.util.Optional; +import java.util.Set; +import org.kie.kogito.internal.process.workitem.InvalidTransitionException; import org.kie.kogito.internal.process.workitem.KogitoWorkItem; import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.internal.process.workitem.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.Policy; +import org.kie.kogito.internal.process.workitem.WorkItemLifeCycle; +import org.kie.kogito.internal.process.workitem.WorkItemLifeCyclePhase; +import org.kie.kogito.internal.process.workitem.WorkItemPhaseState; +import org.kie.kogito.internal.process.workitem.WorkItemTerminationType; import org.kie.kogito.internal.process.workitem.WorkItemTransition; import org.kie.kogito.process.workitems.InternalKogitoWorkItem; import org.kie.kogito.process.workitems.impl.DefaultKogitoWorkItemHandler; +import org.kie.kogito.process.workitems.impl.DefaultWorkItemLifeCycle; +import org.kie.kogito.process.workitems.impl.DefaultWorkItemLifeCyclePhase; import org.kie.kogito.usertask.UserTask; import org.kie.kogito.usertask.UserTaskInstance; import org.kie.kogito.usertask.UserTasks; import org.kie.kogito.usertask.model.UserTaskModel; +import static java.util.Collections.emptyMap; +import static java.util.Optional.ofNullable; + /** * Default Work Item handler based on the standard life cycle */ public class UserTaskKogitoWorkItemHandler extends DefaultKogitoWorkItemHandler { + private static String UT_SEPARATOR = System.getProperty("org.jbpm.ht.user.separator", ","); + + public static final WorkItemPhaseState INACTIVE = WorkItemPhaseState.initialized(); + public static final WorkItemPhaseState COMPLETED = WorkItemPhaseState.of("Completed", WorkItemTerminationType.COMPLETE); + public static final WorkItemPhaseState ABORTED = WorkItemPhaseState.of("Aborted", WorkItemTerminationType.ABORT); + public static final WorkItemPhaseState ACTIVATED = WorkItemPhaseState.of("Activated"); + public static final WorkItemPhaseState RESERVED = WorkItemPhaseState.of("Reserved"); + + public static final WorkItemLifeCyclePhase TRANSITION_RESERVED_COMPLETE = + new DefaultWorkItemLifeCyclePhase("complete", RESERVED, COMPLETED, UserTaskKogitoWorkItemHandler::userTaskCompleteWorkItemHandler); + public static final WorkItemLifeCyclePhase TRANSITION_RESERVED_ABORT = + new DefaultWorkItemLifeCyclePhase("abort", RESERVED, ABORTED, UserTaskKogitoWorkItemHandler::userTaskAbortWorkItemHandler); + public static final WorkItemLifeCyclePhase TRANSITION_ACTIVATED_CLAIM = + new DefaultWorkItemLifeCyclePhase("claim", ACTIVATED, RESERVED, UserTaskKogitoWorkItemHandler::userTaskClaimWorkItemHandler); + public static final WorkItemLifeCyclePhase TRANSITION_CREATED_ACTIVE = + new DefaultWorkItemLifeCyclePhase("activate", INACTIVE, ACTIVATED, UserTaskKogitoWorkItemHandler::userTaskActivateWorkItemHandler); + public static final WorkItemLifeCyclePhase TRANSITION_RESERVED_RELEASE = + new DefaultWorkItemLifeCyclePhase("release", RESERVED, ACTIVATED, UserTaskKogitoWorkItemHandler::userTaskReleaseWorkItemHandler); private static final String DESCRIPTION = "Description"; private static final String PRIORITY = "Priority"; private static final String TASK_NAME = "TaskName"; + private static final String ACTOR_ID = "ActorId"; + private static final String GROUP_ID = "GroupId"; + private static final String BUSINESSADMINISTRATOR_ID = "BusinessAdministratorId"; + private static final String BUSINESSADMINISTRATOR_GROUP_ID = "BusinessAdministratorGroupId"; + private static final String EXCLUDED_OWNER_ID = "ExcludedOwnerId"; @Override public String getName() { @@ -46,38 +82,114 @@ public String getName() { } @Override - public Optional activateWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { + public WorkItemLifeCycle initialize() { + return new DefaultWorkItemLifeCycle(TRANSITION_CREATED_ACTIVE, TRANSITION_ACTIVATED_CLAIM, TRANSITION_RESERVED_RELEASE, TRANSITION_RESERVED_ABORT, + TRANSITION_RESERVED_COMPLETE); + } + + @Override + public WorkItemTransition startingTransition(Map data, Policy... policies) { + return workItemLifeCycle.newTransition(TRANSITION_CREATED_ACTIVE.id(), null, data, policies); + } + + @Override + public WorkItemTransition abortTransition(String phaseStatus, Policy... policies) { + return workItemLifeCycle.newTransition(TRANSITION_RESERVED_ABORT.id(), phaseStatus, emptyMap(), policies); + } + + @Override + public WorkItemTransition completeTransition(String phaseStatus, Map data, Policy... policies) { + return workItemLifeCycle.newTransition(TRANSITION_RESERVED_COMPLETE.id(), phaseStatus, data, policies); + } + + static public Optional userTaskActivateWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { UserTasks userTasks = handler.getApplication().get(UserTasks.class); + Object priority = workItem.getParameter(PRIORITY); + Integer priorityInteger = null; + if (priority instanceof String priorityString) { + priorityInteger = Integer.parseInt((String) priorityString); + } else { + priority = (Integer) priority; + } + UserTask userTask = userTasks.userTaskById((String) workItem.getParameter("id")); UserTaskModel model = userTask.createModel(); model.setTaskName((String) workItem.getParameter(TASK_NAME)); model.setTaskDescription((String) workItem.getParameter(DESCRIPTION)); - model.setTaskPriority((String) workItem.getParameter(PRIORITY)); + model.setTaskPriority(priorityInteger); model.setExternalReferenceId(workItem.getStringId()); - UserTaskInstance instance = userTask.createInstance(model); + ofNullable(workItem.getParameters().get(ACTOR_ID)).map(String.class::cast).map(UserTaskKogitoWorkItemHandler::toSet).ifPresent(model::setPotentialUsers); + ofNullable(workItem.getParameters().get(GROUP_ID)).map(String.class::cast).map(UserTaskKogitoWorkItemHandler::toSet).ifPresent(model::setPotentialGroups); + ofNullable(workItem.getParameters().get(BUSINESSADMINISTRATOR_ID)).map(String.class::cast).map(UserTaskKogitoWorkItemHandler::toSet).ifPresent(model::setAdminUsers); + ofNullable(workItem.getParameters().get(BUSINESSADMINISTRATOR_GROUP_ID)).map(String.class::cast).map(UserTaskKogitoWorkItemHandler::toSet).ifPresent(model::setAdminGroups); + ofNullable(workItem.getParameters().get(EXCLUDED_OWNER_ID)).map(String.class::cast).map(UserTaskKogitoWorkItemHandler::toSet).ifPresent(model::setExcludedUsers); + + UserTaskInstance instance = userTask.createInstance(model); if (workItem instanceof InternalKogitoWorkItem ikw) { ikw.setExternalReferenceId(instance.id()); + ikw.setActualOwner(instance.getActualOwner()); + } + + if (instance.getActualOwner() == null) { + return Optional.empty(); + } else { + return Optional.of(handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), workItem.getPhaseStatus(), emptyMap())); } + } + + static protected Set toSet(String value) { + if (value == null) { + return null; + } + return Set.of(value.split(UT_SEPARATOR)); + } + + static public Optional userTaskClaimWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { + workItem.removeOutput("ACTUAL_OWNER"); + + UserTasks userTasks = handler.getApplication().get(UserTasks.class); + UserTask userTask = userTasks.userTaskById((String) workItem.getParameter("id")); + userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(ut -> { + Map data = transition.data(); + if (!data.containsKey("ACTUAL_OWNER")) { + throw new InvalidTransitionException("transition claim does not contain ACTUAL_OWNER"); + } + ut.setActuaOwner((String) data.get("ACTUAL_OWNER")); + if (workItem instanceof InternalKogitoWorkItem ikw) { + ikw.setActualOwner(ut.getActualOwner()); + } + }); + return Optional.empty(); + } + + static public Optional userTaskReleaseWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { + UserTasks userTasks = handler.getApplication().get(UserTasks.class); + UserTask userTask = userTasks.userTaskById((String) workItem.getParameter("id")); + userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(ut -> { + ut.setActuaOwner(null); + }); return Optional.empty(); } - @Override - public Optional completeWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { + static public Optional userTaskCompleteWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { UserTasks userTasks = handler.getApplication().get(UserTasks.class); UserTask userTask = userTasks.userTaskById((String) workItem.getParameter("id")); - userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(UserTaskInstance::complete); + userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(ut -> { + ut.complete(); + }); return Optional.empty(); } - @Override - public Optional abortWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { + static public Optional userTaskAbortWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { UserTasks userTasks = handler.getApplication().get(UserTasks.class); UserTask userTask = userTasks.userTaskById((String) workItem.getParameter("id")); - userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(UserTaskInstance::abort); + userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(ut -> { + ut.abort(); + }); return Optional.empty(); } } diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTask.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTask.java index dd9e163dd8d..d8042a1d506 100644 --- a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTask.java +++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTask.java @@ -42,7 +42,7 @@ public class DefaultUserTask implements UserTask { private String taskName; private String taskDescription; private String referenceName; - private String taskPriority; + private Integer taskPriority; private Boolean skippable; private Set potentialUsers; private Set potentialGroups; @@ -129,11 +129,11 @@ public void setTaskDescription(String taskDescription) { } @Override - public String getTaskPriority() { + public Integer getTaskPriority() { return this.taskPriority; } - public void setTaskPriority(String taskPriority) { + public void setTaskPriority(Integer taskPriority) { this.taskPriority = taskPriority; } diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskInstance.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskInstance.java index b3711154953..20e318e9b01 100644 --- a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskInstance.java +++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskInstance.java @@ -18,7 +18,9 @@ */ package org.kie.kogito.usertask.impl; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.UUID; import org.kie.kogito.internal.usertask.event.KogitoUserTaskEventSupport; @@ -43,6 +45,13 @@ public class DefaultUserTaskInstance implements UserTaskInstance { public DefaultUserTaskInstance(UserTaskInstances instances, UserTaskModel userTaskModel) { this.id = UUID.randomUUID().toString(); this.userTaskModel = userTaskModel; + + Set potentialUsers = new HashSet<>(this.userTaskModel.getPotentialUsers()); + potentialUsers.removeAll(this.userTaskModel.getExcludedUsers()); + + if (potentialUsers.size() == 1) { + this.actualOwner = potentialUsers.iterator().next(); + } } public void setUserTaskEventSupport(KogitoUserTaskEventSupport userTaskEventSupport) { @@ -74,6 +83,16 @@ public String status() { return status; } + @Override + public boolean hasActualOwner() { + return actualOwner != null; + } + + @Override + public void setActuaOwner(String actualOwner) { + this.actualOwner = actualOwner; + } + @Override public String getActualOwner() { return actualOwner; diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/model/DefaultHumanTaskLifeCycle.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/model/DefaultHumanTaskLifeCycle.java deleted file mode 100644 index 19f6cff027f..00000000000 --- a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/model/DefaultHumanTaskLifeCycle.java +++ /dev/null @@ -1,118 +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.usertask.impl.model; - -import org.kie.kogito.process.workitems.impl.DefaultWorkItemLifeCycle; - -/** - * Base life cycle definition for human tasks. It comes with following phases - * - *
    - *
  • Active
  • - *
  • Claim
  • - *
  • Release
  • - *
  • Complete
  • - *
  • Skip
  • - *
  • Abort
  • - *
- * At the beginning human task enters - * - *
- * Active
- * 
- * - * phase. From there it can go to - * - *
    - *
  • Claim
  • - *
  • Complete
  • - *
  • Skip
  • - *
  • Abort
  • - *
- * - * at any time. At each phase data can be associated and by that set on work item. - */ -public class DefaultHumanTaskLifeCycle extends DefaultWorkItemLifeCycle { - - // private static final Logger logger = LoggerFactory.getLogger(DefaultHumanTaskLifeCycle.class); - // - // private Map phases = new LinkedHashMap<>(); - // - // public DefaultHumanTaskLifeCycle() { - // phases.put(Claim.ID, new Claim()); - // phases.put(Release.ID, new Release()); - // phases.put(Complete.ID, new Complete()); - // phases.put(Skip.ID, new Skip()); - // phases.put(Active.ID, new Active()); - // phases.put(Abort.ID, new Abort()); - // } - // - // @Override - // public WorkItemLifeCyclePhase phaseById(String phaseId) { - // return phases.get(phaseId); - // } - // - // @Override - // public Collection phases() { - // return phases.values(); - // } - // - // @Override - // public Map transitionTo(KogitoWorkItem workItem, KogitoWorkItemManager manager, WorkItemTransition> transition) { - // logger.debug("Transition method invoked for work item {} to transition to {}, currently in phase {} and status {}", workItem.getStringId(), transition.phase(), workItem.getPhaseId(), - // workItem.getPhaseStatus()); - // InternalHumanTaskWorkItem humanTaskWorkItem = (InternalHumanTaskWorkItem) workItem; - // - // WorkItemLifeCyclePhase targetPhase = phases.get(transition.phase()); - // if (targetPhase == null) { - // logger.debug("Target life cycle phase '{}' does not exist in {}", transition.phase(), this.getClass().getSimpleName()); - // throw new InvalidLifeCyclePhaseException(transition.phase()); - // } - // - // WorkItemLifeCyclePhase currentPhase = phases.get(humanTaskWorkItem.getPhaseId()); - // - // if (!targetPhase.canTransition(currentPhase)) { - // logger.debug("Target life cycle phase '{}' cannot transition from current state '{}'", targetPhase.id(), currentPhase.id()); - // throw new InvalidTransitionException("Cannot transition from " + humanTaskWorkItem.getPhaseId() + " to " + targetPhase.id()); - // } - // - // if (!targetPhase.id().equals(Active.ID) && !targetPhase.id().equals(Abort.ID) && !humanTaskWorkItem.enforce(transition.policies().toArray(new Policy[transition.policies().size()]))) { - // throw new NotAuthorizedException("User is not authorized to access task instance with id " + humanTaskWorkItem.getStringId()); - // } - // - // humanTaskWorkItem.setPhaseId(targetPhase.id()); - // humanTaskWorkItem.setPhaseStatus(targetPhase.status()); - // - // targetPhase.apply(humanTaskWorkItem, transition); - // if (transition.data() != null) { - // logger.debug("Updating data for phase {} and work item {}", targetPhase.id(), humanTaskWorkItem.getStringId()); - // humanTaskWorkItem.setResults(transition.data()); - // } - // logger.debug("Transition for work item {} to {} done, currently in phase {} and status {}", workItem.getStringId(), transition.phase(), workItem.getPhaseId(), workItem.getPhaseStatus()); - // - // if (targetPhase.isTerminating()) { - // logger.debug("Target life cycle phase '{}' is terminiating, completing work item {}", targetPhase.id(), humanTaskWorkItem.getStringId()); - // // since target life cycle phase is terminating completing work item - // ((InternalKogitoWorkItemManager) manager).internalCompleteWorkItem(humanTaskWorkItem); - // } - // - // return data(humanTaskWorkItem); - // } - -} diff --git a/jbpm/process-workitems/src/main/java/org/kie/kogito/process/workitems/InternalKogitoWorkItem.java b/jbpm/process-workitems/src/main/java/org/kie/kogito/process/workitems/InternalKogitoWorkItem.java index e375c86f87a..bdfc87e94eb 100755 --- a/jbpm/process-workitems/src/main/java/org/kie/kogito/process/workitems/InternalKogitoWorkItem.java +++ b/jbpm/process-workitems/src/main/java/org/kie/kogito/process/workitems/InternalKogitoWorkItem.java @@ -27,6 +27,8 @@ public interface InternalKogitoWorkItem extends org.drools.core.process.WorkItem void setExternalReferenceId(String id); + void setActualOwner(String owner); + void setProcessInstanceId(String processInstanceId); void setNodeInstanceId(String deploymentId); diff --git a/jbpm/process-workitems/src/main/java/org/kie/kogito/process/workitems/impl/KogitoWorkItemImpl.java b/jbpm/process-workitems/src/main/java/org/kie/kogito/process/workitems/impl/KogitoWorkItemImpl.java index b2ff7f3492f..76690d25586 100755 --- a/jbpm/process-workitems/src/main/java/org/kie/kogito/process/workitems/impl/KogitoWorkItemImpl.java +++ b/jbpm/process-workitems/src/main/java/org/kie/kogito/process/workitems/impl/KogitoWorkItemImpl.java @@ -56,6 +56,7 @@ public class KogitoWorkItemImpl implements InternalKogitoWorkItem, Serializable private transient KogitoNodeInstance nodeInstance; private String externalReferenceId; + private String actualOwner; public void setId(String id) { this.id = id; @@ -229,6 +230,11 @@ public void setCompleteDate(Date completeDate) { this.completeDate = completeDate; } + @Override + public void removeOutput(String name) { + this.results.remove(name); + } + @Override public String toString() { StringBuilder b = new StringBuilder("WorkItem "); @@ -540,4 +546,13 @@ public void setExternalReferenceId(String externalReferenceId) { this.externalReferenceId = id; } + @Override + public String getActualOwner() { + return this.actualOwner; + } + + @Override + public void setActualOwner(String actualOwner) { + this.actualOwner = actualOwner; + } } diff --git a/kogito-codegen-modules/kogito-codegen-api/src/main/java/org/kie/kogito/codegen/api/template/TemplatedGenerator.java b/kogito-codegen-modules/kogito-codegen-api/src/main/java/org/kie/kogito/codegen/api/template/TemplatedGenerator.java index 4d57d572457..0c377046d81 100644 --- a/kogito-codegen-modules/kogito-codegen-api/src/main/java/org/kie/kogito/codegen/api/template/TemplatedGenerator.java +++ b/kogito-codegen-modules/kogito-codegen-api/src/main/java/org/kie/kogito/codegen/api/template/TemplatedGenerator.java @@ -146,7 +146,12 @@ public String uncheckedTemplatePath() { } private InputStream getResource(String path) { - return this.getClass().getResourceAsStream(path); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + InputStream is = classLoader.getResourceAsStream(path); + if (is == null) { + return this.getClass().getResourceAsStream(path); + } + return is; } public static Builder builder() { diff --git a/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/AbstractCodegenIT.java b/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/AbstractCodegenIT.java index 72cb36a45a8..8597571b259 100644 --- a/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/AbstractCodegenIT.java +++ b/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/AbstractCodegenIT.java @@ -36,6 +36,7 @@ import org.drools.codegen.common.GeneratedFile; import org.drools.compiler.compiler.io.memory.MemoryFileSystem; import org.drools.util.PortablePath; +import org.jbpm.process.instance.LightWorkItemManager; import org.junit.platform.commons.util.ClassLoaderUtils; import org.kie.kogito.Application; import org.kie.kogito.codegen.api.AddonsConfig; @@ -47,6 +48,10 @@ import org.kie.kogito.codegen.core.io.CollectedResourceProducer; import org.kie.kogito.codegen.process.ProcessCodegen; import org.kie.kogito.codegen.usertask.UserTaskCodegen; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; +import org.kie.kogito.process.Process; +import org.kie.kogito.process.WorkItem; +import org.kie.kogito.process.impl.AbstractProcess; import org.kie.memorycompiler.CompilationResult; import org.kie.memorycompiler.JavaCompiler; import org.kie.memorycompiler.JavaCompilerFactory; @@ -245,4 +250,8 @@ protected Class findClass(final String name) throws ClassNotFoundException { return super.findClass(name); } } + + protected KogitoWorkItemHandler getWorkItemHandler(Process p, WorkItem workItem) { + return ((LightWorkItemManager) ((AbstractProcess) p).getProcessRuntime().getKogitoWorkItemManager()).getWorkItemHandler(workItem.getId()); + } } diff --git a/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/tests/CallActivityTaskIT.java b/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/tests/CallActivityTaskIT.java index 43bcc1664bf..b78264bb65e 100644 --- a/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/tests/CallActivityTaskIT.java +++ b/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/tests/CallActivityTaskIT.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Map; -import org.jbpm.process.instance.LightWorkItemManager; import org.junit.jupiter.api.Test; import org.kie.kogito.Application; import org.kie.kogito.Model; @@ -35,11 +34,11 @@ import org.kie.kogito.codegen.data.PersonWithAddress; import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.internal.process.workitem.Policy; +import org.kie.kogito.internal.process.workitem.WorkItemTransition; import org.kie.kogito.process.Process; import org.kie.kogito.process.ProcessInstance; import org.kie.kogito.process.Processes; import org.kie.kogito.process.WorkItem; -import org.kie.kogito.process.impl.AbstractProcess; import static org.assertj.core.api.Assertions.assertThat; @@ -154,7 +153,8 @@ public void testCallActivityTaskWithExpressionsForIO() throws Exception { assertThat(wi.getPhaseStatus()).isEqualTo("Activated"); KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); - processInstance.transitionWorkItem(workItems.get(0).getId(), handler.completeTransition(workItems.get(0).getPhaseStatus(), parameters, securityPolicy)); + WorkItemTransition transition = handler.completeTransition(workItems.get(0).getPhaseStatus(), parameters, securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_COMPLETED); } @@ -192,7 +192,8 @@ public void testCallActivityTaskWithExpressionsForIONested() throws Exception { assertThat(wi.getName()).isEqualTo("MyTask"); KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); - processInstance.transitionWorkItem(workItems.get(0).getId(), handler.completeTransition(workItems.get(0).getPhaseStatus(), parameters, securityPolicy)); + WorkItemTransition transition = handler.completeTransition(workItems.get(0).getPhaseStatus(), parameters, securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_COMPLETED); } @@ -220,7 +221,5 @@ public void testBasicCallActivityTaskWithSingleVarExpression() throws Exception .containsEntry("x", "a"); } - private KogitoWorkItemHandler getWorkItemHandler(Process p, WorkItem workItem) { - return ((LightWorkItemManager) ((AbstractProcess) p).getProcessRuntime().getKogitoWorkItemManager()).getWorkItemHandler(workItem.getId()); - } + } diff --git a/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/tests/UserTaskIT.java b/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/tests/UserTaskIT.java index fd4812cdfd1..dc5d85a9343 100644 --- a/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/tests/UserTaskIT.java +++ b/kogito-codegen-modules/kogito-codegen-processes-integration-tests/src/test/java/org/kie/kogito/codegen/tests/UserTaskIT.java @@ -39,7 +39,9 @@ import org.kie.kogito.internal.process.runtime.KogitoProcessInstance; import org.kie.kogito.internal.process.workitem.InvalidTransitionException; import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.NotAuthorizedException; import org.kie.kogito.internal.process.workitem.Policy; +import org.kie.kogito.internal.process.workitem.WorkItemNotFoundException; import org.kie.kogito.internal.process.workitem.WorkItemTransition; import org.kie.kogito.process.Process; import org.kie.kogito.process.ProcessConfig; @@ -49,8 +51,16 @@ import org.kie.kogito.process.WorkItem; import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; +import static org.kie.kogito.jbpm.usertask.handler.UserTaskKogitoWorkItemHandler.ACTIVATED; +import static org.kie.kogito.jbpm.usertask.handler.UserTaskKogitoWorkItemHandler.RESERVED; +import static org.kie.kogito.jbpm.usertask.handler.UserTaskKogitoWorkItemHandler.TRANSITION_ACTIVATED_CLAIM; +import static org.kie.kogito.jbpm.usertask.handler.UserTaskKogitoWorkItemHandler.TRANSITION_RESERVED_COMPLETE; +import static org.kie.kogito.jbpm.usertask.handler.UserTaskKogitoWorkItemHandler.TRANSITION_RESERVED_RELEASE; public class UserTaskIT extends AbstractCodegenIT { @@ -89,8 +99,18 @@ public void afterWorkItemTransition(ProcessWorkItemTransitionEvent event) { List workItems = processInstance.workItems(securityPolicy); assertThat(workItems).hasSize(1); assertThat(workItems.get(0).getName()).isEqualTo("FirstTask"); + WorkItem wi = workItems.get(0); - processInstance.completeWorkItem(workItems.get(0).getId(), null, securityPolicy); + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + transition = handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); workItems = processInstance.workItems(securityPolicy); @@ -100,7 +120,7 @@ public void afterWorkItemTransition(ProcessWorkItemTransitionEvent event) { processInstance.completeWorkItem(workItems.get(0).getId(), null, securityPolicy); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_COMPLETED); - assertThat(workItemTransitionEvents).hasSize(8); + assertThat(workItemTransitionEvents).hasSize(12); } @Test @@ -125,8 +145,16 @@ public void testBasicUserTaskProcessPhases() throws Exception { WorkItem wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("FirstTask"); - KogitoWorkItemHandler handlerht = app.config().get(ProcessConfig.class).workItemHandlers().forName(wi.getName()); - processInstance.transitionWorkItem(workItems.get(0).getId(), handlerht.completeTransition(wi.getPhaseStatus(), parameters, securityPolicy)); + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + transition = handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); @@ -135,8 +163,9 @@ public void testBasicUserTaskProcessPhases() throws Exception { wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("SecondTask"); - KogitoWorkItemHandler handler = app.config().get(ProcessConfig.class).workItemHandlers().forName(wi.getName()); - processInstance.transitionWorkItem(workItems.get(0).getId(), handler.completeTransition(wi.getPhaseStatus(), parameters, securityPolicy)); + handler = getWorkItemHandler(p, wi); + transition = handler.completeTransition(workItems.get(0).getPhaseStatus(), parameters, securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_COMPLETED); } @@ -163,8 +192,9 @@ public void testBasicUserTaskProcessClaimAndCompletePhases() throws Exception { assertThat(wi.getName()).isEqualTo("FirstTask"); assertThat(wi.getResults()).isEmpty(); - KogitoWorkItemHandler handlerht = app.config().get(ProcessConfig.class).workItemHandlers().forName(wi.getName()); - processInstance.transitionWorkItem(workItems.get(0).getId(), handlerht.newTransition("claim", wi.getPhaseStatus(), Collections.singletonMap("test", "value"), securityPolicy)); + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("test", "value"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); @@ -173,18 +203,20 @@ public void testBasicUserTaskProcessClaimAndCompletePhases() throws Exception { wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("FirstTask"); - assertThat(wi.getResults()).hasSize(2) - .containsEntry("test", "value") - .containsEntry("ActorId", "john"); + assertThat(wi.getResults()).hasSize(1) + .containsEntry("test", "value"); + + handler = getWorkItemHandler(p, wi); + transition = handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), wi.getPhaseStatus(), emptyMap(), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); - processInstance.transitionWorkItem(workItems.get(0).getId(), handlerht.completeTransition(wi.getPhaseStatus(), Collections.emptyMap(), securityPolicy)); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); workItems = processInstance.workItems(securityPolicy); assertThat(workItems).hasSize(1); wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("SecondTask"); - assertThat(wi.getPhaseStatus()).isEqualTo("Activated"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); assertThat(wi.getResults()).isEmpty(); processInstance.abort(); @@ -212,34 +244,54 @@ public void testBasicUserTaskProcessReleaseAndCompletePhases() throws Exception assertThat(workItems).hasSize(1); WorkItem wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("FirstTask"); - assertThat(wi.getPhaseStatus()).isEqualTo("Activated"); + assertThat(wi.getPhaseStatus()).isEqualTo(ACTIVATED.getName()); assertThat(wi.getResults()).isEmpty(); - KogitoWorkItemHandler handler = null; - handler = app.config().get(ProcessConfig.class).workItemHandlers().forName(wi.getName()); - String workItemId = wi.getId(); - WorkItemTransition transitionInvalid = handler.newTransition("claim", wi.getPhaseStatus(), Collections.emptyMap(), securityPolicy); - assertThatExceptionOfType(InvalidTransitionException.class).isThrownBy(() -> processInstance.transitionWorkItem(workItemId, transitionInvalid)); + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + String workItemStatus = wi.getPhaseStatus(); + assertThatExceptionOfType(InvalidTransitionException.class).isThrownBy(() -> handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), workItemStatus, emptyMap(), securityPolicy)); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + WorkItemTransition claim = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(wi.getId(), claim); + workItems = processInstance.workItems(securityPolicy); assertThat(workItems).hasSize(1); wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("FirstTask"); - assertThat(wi.getPhaseStatus()).isEqualTo("Activated"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); assertThat(wi.getResults()).isEmpty(); - WorkItemTransition transition = handler.completeTransition(wi.getPhaseStatus(), Collections.emptyMap(), securityPolicy); - processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + WorkItemTransition release = handler.newTransition(TRANSITION_RESERVED_RELEASE.id(), wi.getPhaseStatus(), emptyMap(), securityPolicy); + processInstance.transitionWorkItem(wi.getId(), release); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(ACTIVATED.getName()); + assertThat(wi.getResults()).isEmpty(); + + claim = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(wi.getId(), claim); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + assertThat(wi.getResults()).isEmpty(); + WorkItemTransition transition = handler.completeTransition(wi.getPhaseStatus(), emptyMap(), securityPolicy); + processInstance.transitionWorkItem(wi.getId(), transition); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); workItems = processInstance.workItems(securityPolicy); assertThat(workItems).hasSize(1); wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("SecondTask"); - // assertThat(wi.getPhase()).isEqualTo(Active.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Active.STATUS); + + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); assertThat(wi.getResults()).isEmpty(); processInstance.abort(); @@ -280,25 +332,22 @@ public void afterWorkItemTransition(ProcessWorkItemTransitionEvent event) { assertThat(workItems).hasSize(1); WorkItem wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("FirstTask"); - assertThat(wi.getPhaseStatus()).isEqualTo("Activated"); + assertThat(wi.getPhaseStatus()).isEqualTo(ACTIVATED.getName()); assertThat(wi.getResults()).isEmpty(); - KogitoWorkItemHandler handler = null; - handler = app.config().get(ProcessConfig.class).workItemHandlers().forName(wi.getName()); - WorkItemTransition transition = handler.newTransition("claim", wi.getPhaseStatus(), Collections.singletonMap("test", "value"), securityPolicy); + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("test", "value"), securityPolicy); processInstance.transitionWorkItem(workItems.get(0).getId(), transition); - assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); workItems = processInstance.workItems(securityPolicy); assertThat(workItems).hasSize(1); wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("FirstTask"); - assertThat(wi.getPhaseStatus()).isEqualTo("Reserved"); - assertThat(wi.getResults()).hasSize(2) - .containsEntry("test", "value") - .containsEntry("ActorId", "john"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + assertThat(wi.getResults()).hasSize(1) + .containsEntry("test", "value"); - transition = handler.completeTransition(wi.getPhaseStatus(), Collections.emptyMap(), securityPolicy); + transition = handler.completeTransition(wi.getPhaseStatus(), emptyMap(), securityPolicy); processInstance.transitionWorkItem(workItems.get(0).getId(), transition); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); @@ -307,13 +356,13 @@ public void afterWorkItemTransition(ProcessWorkItemTransitionEvent event) { assertThat(workItems).hasSize(1); wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("SecondTask"); - assertThat(wi.getPhaseStatus()).isEqualTo("Activated"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); assertThat(wi.getResults()).isEmpty(); processInstance.abort(); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ABORTED); - assertThat(workItemTransitionEvents).hasSize(10); + assertThat(workItemTransitionEvents).hasSize(12); } @Test @@ -337,20 +386,21 @@ public void testBasicUserTaskProcessClaimAndCompleteWrongUser() throws Exception assertThat(workItems).hasSize(1); WorkItem wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("FirstTask"); - assertThat(wi.getPhaseStatus()).isEqualTo("Activated"); + assertThat(wi.getPhaseStatus()).isEqualTo(ACTIVATED.getName()); assertThat(wi.getResults()).isEmpty(); final String wiId = wi.getId(); IdentityProvider identity = IdentityProviders.of("kelly"); // if user that is not authorized to work on work item both listing and getting by id should apply it - // List securedWorkItems = processInstance.workItems(SecurityPolicy.of(identity)); - // assertThat(securedWorkItems).isEmpty(); - // assertThatExceptionOfType(WorkItemNotFoundException.class).isThrownBy(() -> processInstance.workItem(wiId, SecurityPolicy.of(identity))); - // - // assertThatExceptionOfType(NotAuthorizedException.class).isThrownBy(() -> processInstance.transitionWorkItem(wiId, new HumanTaskTransition(Claim.ID, null, identity))); - // - // assertThatExceptionOfType(NotAuthorizedException.class).isThrownBy(() -> processInstance.completeWorkItem(wiId, null, SecurityPolicy.of(identity))); + List securedWorkItems = processInstance.workItems(SecurityPolicy.of(identity)); + assertThat(securedWorkItems).isEmpty(); + + assertThatExceptionOfType(WorkItemNotFoundException.class).isThrownBy(() -> processInstance.workItem(wiId, SecurityPolicy.of(identity))); + + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition claimKelly = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "kelly"), SecurityPolicy.of(identity)); + assertThatExceptionOfType(NotAuthorizedException.class).isThrownBy(() -> processInstance.transitionWorkItem(wiId, claimKelly)); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); @@ -358,288 +408,330 @@ public void testBasicUserTaskProcessClaimAndCompleteWrongUser() throws Exception assertThat(workItems).hasSize(1); wi = workItems.get(0); assertThat(wi.getName()).isEqualTo("FirstTask"); - assertThat(wi.getPhaseStatus()).isEqualTo("Activated"); + assertThat(wi.getPhaseStatus()).isEqualTo(ACTIVATED.getName()); assertThat(wi.getResults()).isEmpty(); - IdentityProvider identityCorrect = IdentityProviders.of("john"); - - // processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, null, identityCorrect)); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + WorkItemTransition claimJohn = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(wiId, claimJohn); + workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("SecondTask"); - // assertThat(wi.getPhase()).isEqualTo(Active.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Active.STATUS); - // assertThat(wi.getResults()).isEmpty(); - // - // processInstance.abort(); - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ABORTED); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + assertThat(wi.getResults()).isEmpty(); + WorkItemTransition completeJohn = handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), wi.getPhaseStatus(), emptyMap(), securityPolicy); + processInstance.transitionWorkItem(wiId, completeJohn); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("SecondTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + assertThat(wi.getResults()).isEmpty(); + + processInstance.abort(); + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ABORTED); } @Test public void testApprovalWithExcludedOwnerViaPhases() throws Exception { - // Application app = generateCodeProcessesOnly("usertask/approval.bpmn2"); - // assertThat(app).isNotNull(); - // - // Process p = app.get(Processes.class).processById("approvals"); - // - // Model m = p.createModel(); - // Map parameters = new HashMap<>(); - // m.fromMap(parameters); - // - // ProcessInstance processInstance = p.createInstance(m); - // processInstance.start(); - // assertThat(processInstance.status()).isEqualTo(KogitoProcessInstance.STATE_ACTIVE); - // - // IdentityProvider identity = IdentityProviders.of("admin", Collections.singletonList("managers")); - // SecurityPolicy policy = SecurityPolicy.of(identity); - // - // processInstance.workItems(policy); - // - // List workItems = processInstance.workItems(policy); - // assertThat(workItems).hasSize(1); - // HumanTaskTransition transition = new HumanTaskTransition(Complete.ID, null, identity); - // processInstance.transitionWorkItem(workItems.get(0).getId(), transition); - // // actual owner of the first task is excluded owner on the second task so won't find it - // workItems = processInstance.workItems(policy); - // assertThat(workItems).isEmpty(); - // - // identity = IdentityProviders.of("john", Collections.singletonList("managers")); - // policy = SecurityPolicy.of(identity); - // - // workItems = processInstance.workItems(policy); - // assertThat(workItems).hasSize(1); - // - // transition = new HumanTaskTransition(Complete.ID, null, identity); - // processInstance.transitionWorkItem(workItems.get(0).getId(), transition); - // - // assertThat(processInstance.status()).isEqualTo(KogitoProcessInstance.STATE_COMPLETED); + Application app = generateCodeProcessesOnly("usertask/approval.bpmn2"); + assertThat(app).isNotNull(); + + Process p = app.get(Processes.class).processById("approvals"); + + Model m = p.createModel(); + Map parameters = new HashMap<>(); + m.fromMap(parameters); + + ProcessInstance processInstance = p.createInstance(m); + processInstance.start(); + assertThat(processInstance.status()).isEqualTo(KogitoProcessInstance.STATE_ACTIVE); + + IdentityProvider identity = IdentityProviders.of("manager", emptyList()); + SecurityPolicy policy = SecurityPolicy.of(identity); + + processInstance.workItems(policy); + + List workItems = processInstance.workItems(policy); + assertThat(workItems).hasSize(1); + + WorkItem wi = workItems.get(0); + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition transition = handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), wi.getPhaseStatus(), singletonMap("ActorId", "manager"), policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + // actual owner of the first task is excluded owner on the second task so won't find it + workItems = processInstance.workItems(policy); + assertThat(workItems).isEmpty(); + + identity = IdentityProviders.of("john", singletonList("managers")); + policy = SecurityPolicy.of(identity); + + workItems = processInstance.workItems(policy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + workItems = processInstance.workItems(policy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + transition = handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), wi.getPhaseStatus(), emptyMap(), policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + assertThat(processInstance.status()).isEqualTo(KogitoProcessInstance.STATE_COMPLETED); } @Test public void testApprovalWithExcludedOwner() throws Exception { - // Application app = generateCodeProcessesOnly("usertask/approval.bpmn2"); - // assertThat(app).isNotNull(); - // - // Process p = app.get(Processes.class).processById("approvals"); - // - // Model m = p.createModel(); - // Map parameters = new HashMap<>(); - // m.fromMap(parameters); - // - // ProcessInstance processInstance = p.createInstance(m); - // processInstance.start(); - // assertThat(processInstance.status()).isEqualTo(KogitoProcessInstance.STATE_ACTIVE); - // - // IdentityProvider identity = IdentityProviders.of("admin", Collections.singletonList("managers")); - // SecurityPolicy policy = SecurityPolicy.of(identity); - // - // processInstance.workItems(policy); - // - // List workItems = processInstance.workItems(policy); - // assertThat(workItems).hasSize(1); - // - // processInstance.completeWorkItem(workItems.get(0).getId(), null, policy); - // // actual owner of the first task is excluded owner on the second task so won't find it - // workItems = processInstance.workItems(policy); - // assertThat(workItems).isEmpty(); - // - // identity = IdentityProviders.of("john", Collections.singletonList("managers")); - // policy = SecurityPolicy.of(identity); - // - // workItems = processInstance.workItems(policy); - // assertThat(workItems).hasSize(1); - // - // processInstance.completeWorkItem(workItems.get(0).getId(), null, policy); - // - // assertThat(processInstance.status()).isEqualTo(KogitoProcessInstance.STATE_COMPLETED); + Application app = generateCodeProcessesOnly("usertask/approval.bpmn2"); + assertThat(app).isNotNull(); + + Process p = app.get(Processes.class).processById("approvals"); + + Model m = p.createModel(); + Map parameters = new HashMap<>(); + parameters.put("approver", "manager"); + m.fromMap(parameters); + + ProcessInstance processInstance = p.createInstance(m); + processInstance.start(); + assertThat(processInstance.status()).isEqualTo(KogitoProcessInstance.STATE_ACTIVE); + + IdentityProvider identity = IdentityProviders.of("manager", emptyList()); + SecurityPolicy policy = SecurityPolicy.of(identity); + + List workItems = processInstance.workItems(policy); + assertThat(workItems).hasSize(1); + + processInstance.completeWorkItem(workItems.get(0).getId(), singletonMap("ActorId", "manager"), policy); + // actual owner of the first task is excluded owner on the second task so won't find it + workItems = processInstance.workItems(policy); + assertThat(workItems).isEmpty(); + + identity = IdentityProviders.of("john", Collections.singletonList("managers")); + policy = SecurityPolicy.of(identity); + + workItems = processInstance.workItems(policy); + assertThat(workItems).hasSize(1); + + assertThat(workItems).hasSize(1); + WorkItem wi = workItems.get(0); + + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + processInstance.completeWorkItem(workItems.get(0).getId(), null, policy); + + assertThat(processInstance.status()).isEqualTo(KogitoProcessInstance.STATE_COMPLETED); } @Test public void testBasicUserTaskProcessCancelAndTriggerNode() throws Exception { - // Application app = generateCodeProcessesOnly("usertask/UserTasksProcess.bpmn2"); - // assertThat(app).isNotNull(); - // - // Process p = app.get(Processes.class).processById("UserTasksProcess"); - // - // Model m = p.createModel(); - // Map parameters = new HashMap<>(); - // m.fromMap(parameters); - // - // ProcessInstance processInstance = p.createInstance(m); - // processInstance.start(); - // - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); - // - // List workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // WorkItem wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("FirstTask"); - // assertThat(wi.getPhase()).isEqualTo(Active.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Active.STATUS); - // - // processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, null, securityPolicy)); - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); - // - // workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("SecondTask"); - // assertThat(wi.getPhase()).isEqualTo(Active.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Active.STATUS); - // - // String firstSecondTaskNodeInstanceId = wi.getNodeInstanceId(); - // - // processInstance.cancelNodeInstance(wi.getNodeInstanceId()); - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); - // - // processInstance.triggerNode("UserTask_2"); - // workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("SecondTask"); - // assertThat(wi.getPhase()).isEqualTo(Active.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Active.STATUS); - // // since it was triggered again it must have different node instance id - // assertThat(wi.getNodeInstanceId()).isNotEqualTo(firstSecondTaskNodeInstanceId); - // processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, null, securityPolicy)); - // - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_COMPLETED); + Application app = generateCodeProcessesOnly("usertask/UserTasksProcess.bpmn2"); + assertThat(app).isNotNull(); + + Process p = app.get(Processes.class).processById("UserTasksProcess"); + + Model m = p.createModel(); + Map parameters = new HashMap<>(); + m.fromMap(parameters); + + ProcessInstance processInstance = p.createInstance(m); + processInstance.start(); + + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + + List workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + WorkItem wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(ACTIVATED.getName()); + + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + transition = handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("SecondTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + + String firstSecondTaskNodeInstanceId = wi.getNodeInstanceId(); + + processInstance.cancelNodeInstance(wi.getNodeInstanceId()); + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + + processInstance.triggerNode("UserTask_2"); + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("SecondTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + // since it was triggered again it must have different node instance id + assertThat(wi.getNodeInstanceId()).isNotEqualTo(firstSecondTaskNodeInstanceId); + transition = handler.completeTransition(workItems.get(0).getPhaseStatus(), parameters, securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_COMPLETED); } @Test public void testBasicUserTaskProcessCancelAndRetriggerNode() throws Exception { - // Application app = generateCodeProcessesOnly("usertask/UserTasksProcess.bpmn2"); - // assertThat(app).isNotNull(); - // - // Process p = app.get(Processes.class).processById("UserTasksProcess"); - // - // Model m = p.createModel(); - // Map parameters = new HashMap<>(); - // m.fromMap(parameters); - // - // ProcessInstance processInstance = p.createInstance(m); - // processInstance.start(); - // - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); - // - // List workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // WorkItem wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("FirstTask"); - // assertThat(wi.getPhase()).isEqualTo(Active.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Active.STATUS); - // - // processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, null, securityPolicy)); - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); - // - // workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("SecondTask"); - // assertThat(wi.getPhase()).isEqualTo(Active.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Active.STATUS); - // - // String firstSecondTaskNodeInstanceId = wi.getNodeInstanceId(); - // - // processInstance.retriggerNodeInstance(wi.getNodeInstanceId()); - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); - // - // workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("SecondTask"); - // assertThat(wi.getPhase()).isEqualTo(Active.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Active.STATUS); - // // since it was retriggered it must have different node instance id - // assertThat(wi.getNodeInstanceId()).isNotEqualTo(firstSecondTaskNodeInstanceId); - // processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, null, securityPolicy)); - // - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_COMPLETED); + Application app = generateCodeProcessesOnly("usertask/UserTasksProcess.bpmn2"); + assertThat(app).isNotNull(); + + Process p = app.get(Processes.class).processById("UserTasksProcess"); + + Model m = p.createModel(); + Map parameters = new HashMap<>(); + m.fromMap(parameters); + + ProcessInstance processInstance = p.createInstance(m); + processInstance.start(); + + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + + List workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + WorkItem wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + + assertThat(wi.getPhaseStatus()).isEqualTo(ACTIVATED.getName()); + + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + transition = handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("SecondTask"); + + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + + String firstSecondTaskNodeInstanceId = wi.getNodeInstanceId(); + + processInstance.retriggerNodeInstance(wi.getNodeInstanceId()); + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("SecondTask"); + + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + // since it was retriggered it must have different node instance id + assertThat(wi.getNodeInstanceId()).isNotEqualTo(firstSecondTaskNodeInstanceId); + + transition = handler.completeTransition(workItems.get(0).getPhaseStatus(), parameters, securityPolicy); + processInstance.transitionWorkItem(wi.getId(), transition); + + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_COMPLETED); } @Test public void testBasicUserTaskProcessClaimReleaseClaimAndCompletePhases() throws Exception { - // Application app = generateCodeProcessesOnly("usertask/UserTasksProcess.bpmn2"); - // assertThat(app).isNotNull(); - // - // Process p = app.get(Processes.class).processById("UserTasksProcess"); - // - // Model m = p.createModel(); - // Map parameters = new HashMap<>(); - // m.fromMap(parameters); - // - // ProcessInstance processInstance = p.createInstance(m); - // processInstance.start(); - // - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); - // - // List workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // WorkItem wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("FirstTask"); - // assertThat(wi.getPhase()).isEqualTo(Active.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Active.STATUS); - // assertThat(wi.getResults()).isEmpty(); - // - // processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, Collections.singletonMap("test", "value"), securityPolicy)); - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); - // - // workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("FirstTask"); - // assertThat(wi.getPhase()).isEqualTo(Claim.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Claim.STATUS); - // assertThat(wi.getResults()).hasSize(2) - // .containsEntry("test", "value") - // .containsEntry("ActorId", "john"); - // - // processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Release.ID, null, securityPolicy)); - // - // workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("FirstTask"); - // assertThat(wi.getPhase()).isEqualTo(Release.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Release.STATUS); - // assertThat(wi.getResults()).hasSize(2) - // .containsEntry("test", "value") - // .containsEntry("ActorId", "john"); - // - // processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, Collections.singletonMap("test", "value"), securityPolicy)); - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); - // - // workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("FirstTask"); - // assertThat(wi.getPhase()).isEqualTo(Claim.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Claim.STATUS); - // assertThat(wi.getResults()).hasSize(2) - // .containsEntry("test", "value") - // .containsEntry("ActorId", "john"); - // - // processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, null, securityPolicy)); - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); - // - // workItems = processInstance.workItems(securityPolicy); - // assertThat(workItems).hasSize(1); - // wi = workItems.get(0); - // assertThat(wi.getName()).isEqualTo("SecondTask"); - // assertThat(wi.getPhase()).isEqualTo(Active.ID); - // assertThat(wi.getPhaseStatus()).isEqualTo(Active.STATUS); - // assertThat(wi.getResults()).isEmpty(); - // - // processInstance.abort(); - // assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ABORTED); + Application app = generateCodeProcessesOnly("usertask/UserTasksProcess.bpmn2"); + assertThat(app).isNotNull(); + + Process p = app.get(Processes.class).processById("UserTasksProcess"); + + Model m = p.createModel(); + Map parameters = new HashMap<>(); + m.fromMap(parameters); + + ProcessInstance processInstance = p.createInstance(m); + processInstance.start(); + + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + + List workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + WorkItem wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(ACTIVATED.getName()); + assertThat(wi.getResults()).isEmpty(); + + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("test", "value"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + assertThat(wi.getResults()).hasSize(1) + .containsEntry("test", "value"); + + transition = handler.newTransition(TRANSITION_RESERVED_RELEASE.id(), wi.getPhaseStatus(), emptyMap(), securityPolicy); + + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(ACTIVATED.getName()); + assertThat(wi.getResults()).hasSize(0); + + transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("test", "value"), securityPolicy); + processInstance.transitionWorkItem(wi.getId(), transition); + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + assertThat(wi.getResults()).hasSize(1) + .containsEntry("test", "value"); + + transition = handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), wi.getPhaseStatus(), emptyMap(), securityPolicy); + processInstance.transitionWorkItem(wi.getId(), transition); + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("SecondTask"); + assertThat(wi.getPhaseStatus()).isEqualTo(RESERVED.getName()); + assertThat(wi.getResults()).isEmpty(); + + processInstance.abort(); + assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ABORTED); } @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -785,7 +877,7 @@ public void testUserTaskWithIOexpressionProcess() throws Exception { assertThat(workItems.get(0).getName()).isEqualTo("Hello"); assertThat(workItems.get(0).getParameters()).containsEntry("personName", "john"); - processInstance.completeWorkItem(workItems.get(0).getId(), Collections.singletonMap("personAge", 50), securityPolicy); + processInstance.completeWorkItem(workItems.get(0).getId(), singletonMap("personAge", 50), securityPolicy); assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_COMPLETED); Model output = (Model) processInstance.variables(); @@ -822,9 +914,18 @@ public void testBasicUserTaskProcessWithBusinessKey() throws Exception { List workItems = processInstance.workItems(securityPolicy); assertThat(workItems).hasSize(1); assertThat(workItems.get(0).getName()).isEqualTo("FirstTask"); + WorkItem wi = workItems.get(0); - processInstance.completeWorkItem(workItems.get(0).getId(), null, securityPolicy); - assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE); + KogitoWorkItemHandler handler = getWorkItemHandler(p, wi); + WorkItemTransition transition = handler.newTransition(TRANSITION_ACTIVATED_CLAIM.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); + + workItems = processInstance.workItems(securityPolicy); + assertThat(workItems).hasSize(1); + wi = workItems.get(0); + assertThat(wi.getName()).isEqualTo("FirstTask"); + transition = handler.newTransition(TRANSITION_RESERVED_COMPLETE.id(), wi.getPhaseStatus(), singletonMap("ACTUAL_OWNER", "john"), securityPolicy); + processInstance.transitionWorkItem(workItems.get(0).getId(), transition); workItems = processInstance.workItems(securityPolicy); assertThat(workItems).hasSize(1); diff --git a/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/usertask/UserTaskCodegen.java b/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/usertask/UserTaskCodegen.java index 29e4aad086f..01064cdb3fc 100644 --- a/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/usertask/UserTaskCodegen.java +++ b/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/usertask/UserTaskCodegen.java @@ -61,6 +61,7 @@ import com.github.javaparser.ast.body.ConstructorDeclaration; import com.github.javaparser.ast.expr.CastExpr; import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.IntegerLiteralExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NullLiteralExpr; import com.github.javaparser.ast.expr.StringLiteralExpr; @@ -141,7 +142,7 @@ protected Collection internalGenerate() { ConstructorDeclaration declaration = clazzDeclaration.findFirst(ConstructorDeclaration.class).get(); declaration.setName(className); - String taskNodeName = (String) info.getParameter(TASK_NAME); + String taskNodeName = (String) info.getParameter(NODE_NAME); Expression taskNameExpression = taskNodeName != null ? new StringLiteralExpr(taskNodeName) : new NullLiteralExpr(); BlockStmt block = declaration.getBody(); @@ -157,7 +158,7 @@ protected Collection internalGenerate() { block.addStatement(new MethodCallExpr(new ThisExpr(), "setExcludedUsers", NodeList.nodeList(toStringExpression(info.getParameter(EXCLUDED_OWNER_ID))))); block.addStatement(new MethodCallExpr(new ThisExpr(), "setTaskDescription", NodeList.nodeList(toStringExpression(info.getParameter(DESCRIPTION))))); - block.addStatement(new MethodCallExpr(new ThisExpr(), "setTaskPriority", NodeList.nodeList(toStringExpression(info.getParameter(PRIORITY))))); + block.addStatement(new MethodCallExpr(new ThisExpr(), "setTaskPriority", NodeList.nodeList(toIntegerExpression(info.getParameter(PRIORITY))))); block.addStatement(new MethodCallExpr(new ThisExpr(), "setReferenceName", NodeList.nodeList(toStringExpression(info.getParameter(NODE_NAME))))); block.addStatement(new MethodCallExpr(new ThisExpr(), "setSkippable", NodeList.nodeList(toStringExpression(info.getParameter("Skippable"))))); @@ -172,6 +173,14 @@ protected Collection internalGenerate() { return generatedFiles; } + private Expression toIntegerExpression(Object value) { + if (value == null) { + return new CastExpr(StaticJavaParser.parseType(Integer.class.getName()), new NullLiteralExpr()); + } + + return new IntegerLiteralExpr(value.toString()); + } + private Expression toStringExpression(Object value) { if (value == null) { return new CastExpr(StaticJavaParser.parseType(String.class.getName()), new NullLiteralExpr());