diff --git a/addons/common/persistence/ddl/pom.xml b/addons/common/persistence/ddl/pom.xml
index a96bf50824c..7a6519a2fbf 100644
--- a/addons/common/persistence/ddl/pom.xml
+++ b/addons/common/persistence/ddl/pom.xml
@@ -62,17 +62,4 @@
-
-
- productized
-
-
- productized
-
-
-
- src/assembly/productized-db-scripts.xml
-
-
-
\ No newline at end of file
diff --git a/addons/common/persistence/ddl/src/assembly/productized-db-scripts.xml b/addons/common/persistence/ddl/src/assembly/productized-db-scripts.xml
deleted file mode 100644
index 39ec204674d..00000000000
--- a/addons/common/persistence/ddl/src/assembly/productized-db-scripts.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
- db-scripts
-
- zip
-
- false
-
-
- ${path.to.persistence.modules}/jdbc/src/main/resources/kie-flyway/db/postgresql
- postgresql
-
- *.sql
-
-
-
-
diff --git a/addons/common/persistence/postgresql/.gitignore b/addons/common/persistence/postgresql/.gitignore
deleted file mode 100644
index 423a2b902f1..00000000000
--- a/addons/common/persistence/postgresql/.gitignore
+++ /dev/null
@@ -1,20 +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.
-###
-
-/src/main/resources/kie-flyway/db/persistence-postgresql/postgresql/*
\ No newline at end of file
diff --git a/addons/common/persistence/postgresql/pom.xml b/addons/common/persistence/postgresql/pom.xml
index 581d6edf9f2..4b3048dbdba 100644
--- a/addons/common/persistence/postgresql/pom.xml
+++ b/addons/common/persistence/postgresql/pom.xml
@@ -1,4 +1,4 @@
-
+
org.apache.maven.plugins
maven-resources-plugin
@@ -139,10 +130,10 @@
copy-resources
- ${path.to.migration.scripts.to}
+ ${path.to.migration.scripts.target}
- ${path.to.migration.scripts.from}
+ ${path.to.migration.scripts.source}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/internal/process/workitem/KogitoWorkItemHandlerFactory.java b/api/kogito-api/src/main/java/org/kie/kogito/internal/process/workitem/KogitoWorkItemHandlerFactory.java
index 0b9438bb8c1..307bbb2eedb 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/internal/process/workitem/KogitoWorkItemHandlerFactory.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/internal/process/workitem/KogitoWorkItemHandlerFactory.java
@@ -26,7 +26,7 @@ public interface KogitoWorkItemHandlerFactory {
public static List findAllKogitoWorkItemHandlersRegistered() {
List handlers = new ArrayList<>();
- ServiceLoader.load(KogitoWorkItemHandlerFactory.class).stream()
+ ServiceLoader.load(KogitoWorkItemHandlerFactory.class, Thread.currentThread().getContextClassLoader()).stream()
.map(ServiceLoader.Provider::get)
.map(KogitoWorkItemHandlerFactory::provide)
.flatMap(List::stream)
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/internal/usertask/event/KogitoUserTaskEventSupport.java b/api/kogito-api/src/main/java/org/kie/kogito/internal/usertask/event/KogitoUserTaskEventSupport.java
index 4adc903a217..5ec63f27040 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/internal/usertask/event/KogitoUserTaskEventSupport.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/internal/usertask/event/KogitoUserTaskEventSupport.java
@@ -23,6 +23,7 @@
import org.kie.kogito.usertask.UserTaskEventListener;
import org.kie.kogito.usertask.UserTaskInstance;
+import org.kie.kogito.usertask.lifecycle.UserTaskState;
import org.kie.kogito.usertask.model.Attachment;
import org.kie.kogito.usertask.model.Comment;
@@ -37,7 +38,7 @@ enum AssignmentType {
void fireOneUserTaskStateChange(
UserTaskInstance instance,
- String oldPhaseStatus, String newPhaseStatus);
+ UserTaskState oldPhaseStatus, UserTaskState newPhaseStatus);
void fireOnUserTaskNotStartedDeadline(
UserTaskInstance instance,
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/process/workitem/TaskMetaEntity.java b/api/kogito-api/src/main/java/org/kie/kogito/process/workitem/TaskMetaEntity.java
index 84f07f496ab..49150a0af6a 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/process/workitem/TaskMetaEntity.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/process/workitem/TaskMetaEntity.java
@@ -57,6 +57,10 @@ public String getUpdatedBy() {
return updatedBy;
}
+ public void setId(K id) {
+ this.id = id;
+ }
+
public K getId() {
return id;
}
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 8910256e68d..11d762195a5 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
@@ -109,4 +109,6 @@ public interface UserTask {
Collection> getNotCompletedReassigments();
+ UserTaskAssignmentStrategy getAssignmentStrategy();
+
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskAssignmentStrategy.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskAssignmentStrategy.java
new file mode 100644
index 00000000000..985a5d25572
--- /dev/null
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskAssignmentStrategy.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+import java.util.Optional;
+
+import org.kie.kogito.auth.IdentityProvider;
+
+public interface UserTaskAssignmentStrategy {
+
+ static final String DEFAULT_NAME = "default";
+
+ default String getName() {
+ return getClass().getName();
+ }
+
+ Optional computeAssigment(UserTaskInstance userTaskInstance, IdentityProvider identityProvider);
+
+}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskAssignmentStrategyConfig.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskAssignmentStrategyConfig.java
new file mode 100644
index 00000000000..b9bc180a529
--- /dev/null
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskAssignmentStrategyConfig.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+import java.util.List;
+
+public interface UserTaskAssignmentStrategyConfig {
+
+ List userTaskAssignmentStrategies();
+
+ UserTaskAssignmentStrategy forName(String name);
+
+ default UserTaskAssignmentStrategy defaultUserTaskAssignmentStrategy() {
+ return forName(UserTaskAssignmentStrategy.DEFAULT_NAME);
+ }
+}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskConfig.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskConfig.java
index ee031f84188..2bebb31ef62 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskConfig.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskConfig.java
@@ -28,6 +28,8 @@ public interface UserTaskConfig extends KogitoConfig {
UserTaskEventListenerConfig userTaskEventListeners();
+ UserTaskAssignmentStrategyConfig userTaskAssignmentStrategies();
+
UserTaskLifeCycle userTaskLifeCycle();
UnitOfWorkManager unitOfWorkManager();
@@ -36,4 +38,6 @@ public interface UserTaskConfig extends KogitoConfig {
IdentityProvider identityProvider();
+ UserTaskInstances userTaskInstances();
+
}
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 9e73f146240..4a0023a0c41 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
@@ -22,8 +22,8 @@
import java.util.Map;
import java.util.Set;
+import org.kie.kogito.auth.IdentityProvider;
import org.kie.kogito.usertask.lifecycle.UserTaskState;
-import org.kie.kogito.usertask.lifecycle.UserTaskTransitionToken;
import org.kie.kogito.usertask.model.Attachment;
import org.kie.kogito.usertask.model.Comment;
@@ -35,19 +35,15 @@ public interface UserTaskInstance {
UserTaskState getStatus();
+ String getUserTaskId();
+
boolean hasActualOwner();
- void setActuaOwner(String string);
+ void setActuaOwner(String actualOwner);
String getActualOwner();
- UserTaskTransitionToken createTransitionToken(String transitionId, Map data);
-
- void transition(UserTaskTransitionToken token);
-
- void complete();
-
- void abort();
+ void transition(String transitionId, Map data, IdentityProvider identityProvider);
String getExternalReferenceId();
@@ -59,6 +55,14 @@ public interface UserTaskInstance {
Map getMetadata();
+ Map getOutputs();
+
+ Map getInputs();
+
+ void setInput(String key, Object value);
+
+ void setOutput(String key, Object value);
+
/**
* Returns potential users that can work on this task
*
@@ -94,23 +98,24 @@ public interface UserTaskInstance {
*/
Set getExcludedUsers();
- void addAttachment(Attachment attachment);
+ Attachment findAttachmentById(String attachmentId);
- void updateAttachment(Attachment newAttachment);
+ Attachment addAttachment(Attachment attachment);
- void removeAttachment(Attachment oldAttachment);
+ Attachment updateAttachment(Attachment newAttachment);
- void addComment(Comment comment);
+ Attachment removeAttachment(Attachment oldAttachment);
- void updateComment(Comment newComment);
+ Collection getAttachments();
- void removeComment(Comment comment);
+ Comment findCommentById(String commentId);
- Collection getComments();
+ Comment addComment(Comment comment);
- Collection getAttachments();
+ Comment updateComment(Comment newComment);
- Attachment findAttachmentById(String attachmentId);
+ Comment removeComment(Comment comment);
+
+ Collection getComments();
- Comment findCommentById(String commentId);
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskInstances.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskInstances.java
index 57e956bd87f..7f294b15fed 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskInstances.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskInstances.java
@@ -18,11 +18,20 @@
*/
package org.kie.kogito.usertask;
+import java.util.List;
import java.util.Optional;
import java.util.function.Function;
+import org.kie.kogito.auth.IdentityProvider;
+
public interface UserTaskInstances {
+ void setReconnectUserTaskInstance(Function reconnectUserTaskInstance);
+
+ void setDisconnectUserTaskInstance(Function disconnectUserTaskInstance);
+
+ List findByIdentity(IdentityProvider identityProvider);
+
Optional findById(String userTaskInstanceId);
boolean exists(String userTaskInstanceId);
@@ -33,8 +42,4 @@ public interface UserTaskInstances {
UserTaskInstance remove(String userTaskInstanceId);
- void setReconnectUserTaskInstance(Function reconnectUserTaskInstance);
-
- void setDisconnectUserTaskInstance(Function disconnectUserTaskInstance);
-
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskService.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskService.java
new file mode 100644
index 00000000000..70cfdfbdc25
--- /dev/null
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTaskService.java
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.kie.kogito.auth.IdentityProvider;
+import org.kie.kogito.usertask.model.Attachment;
+import org.kie.kogito.usertask.model.Comment;
+import org.kie.kogito.usertask.view.UserTaskTransitionView;
+import org.kie.kogito.usertask.view.UserTaskView;
+
+public interface UserTaskService {
+
+ Optional getUserTaskInstance(String taskId, IdentityProvider identity);
+
+ List list(IdentityProvider identity);
+
+ Optional transition(String taskId, String transitionId, Map data, IdentityProvider identity);
+
+ List allowedTransitions(String taskId, IdentityProvider identity);
+
+ Optional setOutputs(String taskId, Map data, IdentityProvider identity);
+
+ Optional setInputs(String taskId, Map data, IdentityProvider identity);
+
+ List getComments(String taskId, IdentityProvider identity);
+
+ Optional getComment(String taskId, String commentId, IdentityProvider identity);
+
+ Optional addComment(String taskId, Comment comment, IdentityProvider identity);
+
+ Optional updateComment(String taskId, Comment comment, IdentityProvider identity);
+
+ Optional removeComment(String taskId, String commentId, IdentityProvider identity);
+
+ List getAttachments(String taskId, IdentityProvider identity);
+
+ Optional getAttachment(String taskId, String commentId, IdentityProvider identity);
+
+ Optional addAttachment(String taskId, Attachment comment, IdentityProvider identity);
+
+ Optional updateAttachment(String taskId, Attachment comment, IdentityProvider identity);
+
+ Optional removeAttachment(String taskId, String commentId, IdentityProvider identity);
+}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTasks.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTasks.java
index 3d31047cad2..0253644c0f2 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTasks.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/UserTasks.java
@@ -24,6 +24,8 @@
public interface UserTasks extends KogitoEngine {
+ UserTaskInstances instances();
+
UserTask userTaskById(String userTaskId);
Collection userTaskIds();
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/events/UserTaskStateEvent.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/events/UserTaskStateEvent.java
index 196b76aafbb..e5471cc96f3 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/events/UserTaskStateEvent.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/events/UserTaskStateEvent.java
@@ -19,10 +19,12 @@
package org.kie.kogito.usertask.events;
+import org.kie.kogito.usertask.lifecycle.UserTaskState;
+
public interface UserTaskStateEvent extends UserTaskEvent {
- String getNewStatus();
+ UserTaskState getNewStatus();
- String getOldStatus();
+ UserTaskState getOldStatus();
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskLifeCycle.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskLifeCycle.java
index eb8290884a9..09170f4d1cc 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskLifeCycle.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskLifeCycle.java
@@ -19,14 +19,16 @@
package org.kie.kogito.usertask.lifecycle;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
+import org.kie.kogito.auth.IdentityProvider;
import org.kie.kogito.usertask.UserTaskInstance;
public interface UserTaskLifeCycle {
- Optional transition(UserTaskInstance userTaskInstance, UserTaskTransitionToken transition);
+ Optional transition(UserTaskInstance userTaskInstance, UserTaskTransitionToken transition, IdentityProvider identity);
UserTaskTransitionToken newTransitionToken(String transitionId, UserTaskInstance userTaskInstance, Map data);
@@ -34,4 +36,6 @@ public interface UserTaskLifeCycle {
UserTaskTransitionToken newAbortTransitionToken(UserTaskInstance userTaskInstance, Map emptyMap);
+ List allowedTransitions(UserTaskInstance ut);
+
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskState.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskState.java
index 71ba89b94d0..63a3242ede4 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskState.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskState.java
@@ -19,7 +19,6 @@
package org.kie.kogito.usertask.lifecycle;
import java.util.Objects;
-import java.util.Optional;
public class UserTaskState {
@@ -69,8 +68,8 @@ public String getName() {
return name;
}
- public Optional isTerminate() {
- return Optional.ofNullable(terminate);
+ public boolean isTerminate() {
+ return terminate != null;
}
@Override
@@ -91,7 +90,7 @@ public boolean equals(Object obj) {
}
public static UserTaskState initalized() {
- return of(null);
+ return of("Created");
}
@Override
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionException.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionException.java
new file mode 100644
index 00000000000..3e98d19bdc4
--- /dev/null
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionException.java
@@ -0,0 +1,29 @@
+/*
+ * 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.lifecycle;
+
+public class UserTaskTransitionException extends RuntimeException {
+
+ private static final long serialVersionUID = -9127576077607542859L;
+
+ public UserTaskTransitionException(String msg) {
+ super(msg);
+ }
+
+}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionExecutor.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionExecutor.java
index 6124901d28f..79eb36a5a0f 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionExecutor.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionExecutor.java
@@ -20,10 +20,11 @@
import java.util.Optional;
+import org.kie.kogito.auth.IdentityProvider;
import org.kie.kogito.usertask.UserTaskInstance;
public interface UserTaskTransitionExecutor {
- Optional execute(UserTaskInstance transition, UserTaskTransitionToken token);
+ Optional execute(UserTaskInstance transition, UserTaskTransitionToken token, IdentityProvider identity);
}
\ No newline at end of file
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionToken.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionToken.java
index db1dd9e8d72..8277f4d6d56 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionToken.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/lifecycle/UserTaskTransitionToken.java
@@ -22,7 +22,11 @@
public interface UserTaskTransitionToken {
- UserTaskTransition transition();
+ String transitionId();
+
+ UserTaskState source();
+
+ UserTaskState target();
Map data();
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/Attachment.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/Attachment.java
index 04ff75b130a..d032eca9eaf 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/Attachment.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/Attachment.java
@@ -27,6 +27,10 @@ public class Attachment extends TaskMetaEntity {
private static final long serialVersionUID = 1L;
private String name;
+ public Attachment() {
+
+ }
+
public Attachment(String id, String user) {
super(id, user);
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/Comment.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/Comment.java
index 74a801b7112..fe2a3fdf457 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/Comment.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/Comment.java
@@ -24,6 +24,9 @@ public class Comment extends TaskMetaEntity {
private static final long serialVersionUID = -9106249675352498780L;
+ public Comment() {
+ }
+
public Comment(String id, String user) {
super(id, user);
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/CommentInfo.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/CommentInfo.java
new file mode 100644
index 00000000000..5cbfd1404ba
--- /dev/null
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/model/CommentInfo.java
@@ -0,0 +1,40 @@
+/*
+ * 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.model;
+
+public class CommentInfo {
+
+ private String comment;
+
+ public CommentInfo() {
+
+ }
+
+ public CommentInfo(String comment) {
+ this.comment = comment;
+ }
+
+ public String getComment() {
+ return comment;
+ }
+
+ public void setComment(String comment) {
+ this.comment = comment;
+ }
+}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/view/UserTaskTransitionView.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/view/UserTaskTransitionView.java
new file mode 100644
index 00000000000..3f22f091e7c
--- /dev/null
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/view/UserTaskTransitionView.java
@@ -0,0 +1,53 @@
+/*
+ * 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.view;
+
+import org.kie.kogito.usertask.lifecycle.UserTaskState;
+
+public class UserTaskTransitionView {
+
+ private String transitionId;
+ private UserTaskState source;
+ private UserTaskState target;
+
+ public String getTransitionId() {
+ return transitionId;
+ }
+
+ public void setTransitionId(String transitionId) {
+ this.transitionId = transitionId;
+ }
+
+ public UserTaskState getSource() {
+ return source;
+ }
+
+ public void setSource(UserTaskState source) {
+ this.source = source;
+ }
+
+ public UserTaskState getTarget() {
+ return target;
+ }
+
+ public void setTarget(UserTaskState target) {
+ this.target = target;
+ }
+
+}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/usertask/view/UserTaskView.java b/api/kogito-api/src/main/java/org/kie/kogito/usertask/view/UserTaskView.java
new file mode 100644
index 00000000000..660ea4c8446
--- /dev/null
+++ b/api/kogito-api/src/main/java/org/kie/kogito/usertask/view/UserTaskView.java
@@ -0,0 +1,178 @@
+/*
+ * 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.view;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.kie.kogito.usertask.lifecycle.UserTaskState;
+
+public class UserTaskView {
+
+ private String id;
+
+ private String userTaskId;
+
+ private UserTaskState status;
+
+ private String taskName;
+ private String taskDescription;
+ private Integer taskPriority;
+ private Set potentialUsers;
+ private Set potentialGroups;
+ private Set adminUsers;
+ private Set adminGroups;
+ private Set excludedUsers;
+ private String externalReferenceId;
+ private String actualOwner;
+
+ private Map inputs;
+ private Map outputs;
+
+ private Map metadata;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getUserTaskId() {
+ return userTaskId;
+ }
+
+ public void setUserTaskId(String userTaskId) {
+ this.userTaskId = userTaskId;
+ }
+
+ public UserTaskState getStatus() {
+ return status;
+ }
+
+ public void setStatus(UserTaskState status) {
+ this.status = status;
+ }
+
+ public String getTaskName() {
+ return taskName;
+ }
+
+ public void setTaskName(String taskName) {
+ this.taskName = taskName;
+ }
+
+ public String getTaskDescription() {
+ return taskDescription;
+ }
+
+ public void setTaskDescription(String taskDescription) {
+ this.taskDescription = taskDescription;
+ }
+
+ public Integer getTaskPriority() {
+ return taskPriority;
+ }
+
+ public void setTaskPriority(Integer taskPriority) {
+ this.taskPriority = taskPriority;
+ }
+
+ public Set getPotentialUsers() {
+ return potentialUsers;
+ }
+
+ public void setPotentialUsers(Set potentialUsers) {
+ this.potentialUsers = potentialUsers;
+ }
+
+ public Set getPotentialGroups() {
+ return potentialGroups;
+ }
+
+ public void setPotentialGroups(Set potentialGroups) {
+ this.potentialGroups = potentialGroups;
+ }
+
+ public Set getAdminUsers() {
+ return adminUsers;
+ }
+
+ public void setAdminUsers(Set adminUsers) {
+ this.adminUsers = adminUsers;
+ }
+
+ public Set getAdminGroups() {
+ return adminGroups;
+ }
+
+ public void setAdminGroups(Set adminGroups) {
+ this.adminGroups = adminGroups;
+ }
+
+ public Set getExcludedUsers() {
+ return excludedUsers;
+ }
+
+ public void setExcludedUsers(Set excludedUsers) {
+ this.excludedUsers = excludedUsers;
+ }
+
+ public String getExternalReferenceId() {
+ return externalReferenceId;
+ }
+
+ public void setExternalReferenceId(String externalReferenceId) {
+ this.externalReferenceId = externalReferenceId;
+ }
+
+ public String getActualOwner() {
+ return actualOwner;
+ }
+
+ public void setActualOwner(String actualOwner) {
+ this.actualOwner = actualOwner;
+ }
+
+ public Map getInputs() {
+ return inputs;
+ }
+
+ public void setInputs(Map inputs) {
+ this.inputs = inputs;
+ }
+
+ public Map getOutputs() {
+ return outputs;
+ }
+
+ public void setOutputs(Map outputs) {
+ this.outputs = outputs;
+ }
+
+ public Map getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(Map metadata) {
+ this.metadata = metadata;
+ }
+
+}
diff --git a/api/kogito-events-core/src/main/java/org/kie/kogito/event/AbstractDataEvent.java b/api/kogito-events-core/src/main/java/org/kie/kogito/event/AbstractDataEvent.java
index 2fcdd704196..065111c8519 100644
--- a/api/kogito-events-core/src/main/java/org/kie/kogito/event/AbstractDataEvent.java
+++ b/api/kogito-events-core/src/main/java/org/kie/kogito/event/AbstractDataEvent.java
@@ -177,6 +177,15 @@ public abstract class AbstractDataEvent implements DataEvent {
protected AbstractDataEvent() {
}
+ protected AbstractDataEvent(String type, URI source, T body) {
+ this.specVersion = SpecVersion.parse(SPEC_VERSION);
+ this.id = UUID.randomUUID().toString();
+ this.source = source;
+ this.type = type;
+ this.time = ZonedDateTime.now().toOffsetDateTime();
+ this.data = body;
+ }
+
protected AbstractDataEvent(String type,
String source,
T body,
@@ -201,12 +210,7 @@ protected AbstractDataEvent(String type,
String subject,
String dataContentType,
String dataSchema) {
- this.specVersion = SpecVersion.parse(SPEC_VERSION);
- this.id = UUID.randomUUID().toString();
- this.source = Optional.ofNullable(source).map(URI::create).orElse(null);
- this.type = type;
- this.time = ZonedDateTime.now().toOffsetDateTime();
- this.data = body;
+ this(type, Optional.ofNullable(source).map(URI::create).orElse(null), body);
setKogitoProcessInstanceId(kogitoProcessInstanceId);
setKogitoRootProcessInstanceId(kogitoRootProcessInstanceId);
setKogitoProcessId(kogitoProcessId);
diff --git a/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/DefaultInstanceEventBatch.java b/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/DefaultInstanceEventBatch.java
index c4f6cd76b2f..df94b1183ae 100644
--- a/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/DefaultInstanceEventBatch.java
+++ b/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/DefaultInstanceEventBatch.java
@@ -68,7 +68,7 @@ public int compare(DataEvent> event1, DataEvent> event2) {
@Override
public void append(Object event) {
- LOG.info("event generated {}", event);
+ LOG.trace("event generated {}", event);
this.dataEventAdapters.stream().filter(a -> a.accept(event)).map(a -> a.adapt(event)).forEach(this.processedEvents::add);
}
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 fe577ac0c29..af70b37ae35 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
@@ -54,9 +54,9 @@ public DataEvent> adapt(Object payload) {
.userTaskDescription(event.getUserTaskInstance().getTaskDescription())
.userTaskPriority(priorityStr)
.userTaskReferenceName(event.getUserTask().getReferenceName())
- .state(event.getNewStatus())
+ .state(event.getNewStatus().getName())
.actualOwner(event.getUserTaskInstance().getActualOwner())
- .eventType(isTransition(event) ? event.getNewStatus() : "Modify")
+ .eventType(isTransition(event) ? event.getNewStatus().getName() : "Modify")
.processInstanceId((String) event.getUserTaskInstance().getMetadata().get("ProcessInstanceId"));
UserTaskInstanceStateEventBody body = builder.build();
diff --git a/api/kogito-events-core/src/main/java/org/kie/kogito/event/process/MultipleProcessInstanceDataEvent.java b/api/kogito-events-core/src/main/java/org/kie/kogito/event/process/MultipleProcessInstanceDataEvent.java
new file mode 100644
index 00000000000..7db8c0e7659
--- /dev/null
+++ b/api/kogito-events-core/src/main/java/org/kie/kogito/event/process/MultipleProcessInstanceDataEvent.java
@@ -0,0 +1,34 @@
+/*
+ * 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.event.process;
+
+import java.net.URI;
+import java.util.Collection;
+
+public class MultipleProcessInstanceDataEvent extends ProcessInstanceDataEvent>> {
+
+ public static final String TYPE = "MultipleProcessInstanceDataEvent";
+
+ public MultipleProcessInstanceDataEvent() {
+ }
+
+ public MultipleProcessInstanceDataEvent(URI source, Collection> body) {
+ super(TYPE, source, body);
+ }
+}
diff --git a/api/kogito-events-core/src/main/java/org/kie/kogito/event/process/ProcessInstanceDataEvent.java b/api/kogito-events-core/src/main/java/org/kie/kogito/event/process/ProcessInstanceDataEvent.java
index 8069df7ee39..31131563dcc 100644
--- a/api/kogito-events-core/src/main/java/org/kie/kogito/event/process/ProcessInstanceDataEvent.java
+++ b/api/kogito-events-core/src/main/java/org/kie/kogito/event/process/ProcessInstanceDataEvent.java
@@ -18,6 +18,8 @@
*/
package org.kie.kogito.event.process;
+import java.net.URI;
+
import org.kie.kogito.event.AbstractDataEvent;
public class ProcessInstanceDataEvent extends AbstractDataEvent {
@@ -29,6 +31,10 @@ public ProcessInstanceDataEvent(T body) {
setData(body);
}
+ protected ProcessInstanceDataEvent(String type, URI source, T body) {
+ super(type, source, body);
+ }
+
public ProcessInstanceDataEvent(String type,
String source,
T body,
diff --git a/api/kogito-events-core/src/main/java/org/kie/kogito/event/usertask/MultipleUserTaskInstanceDataEvent.java b/api/kogito-events-core/src/main/java/org/kie/kogito/event/usertask/MultipleUserTaskInstanceDataEvent.java
new file mode 100644
index 00000000000..b2b62c61d83
--- /dev/null
+++ b/api/kogito-events-core/src/main/java/org/kie/kogito/event/usertask/MultipleUserTaskInstanceDataEvent.java
@@ -0,0 +1,34 @@
+/*
+ * 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.event.usertask;
+
+import java.net.URI;
+import java.util.Collection;
+
+public class MultipleUserTaskInstanceDataEvent extends UserTaskInstanceDataEvent>> {
+
+ public static final String TYPE = "MultipleUserTaskInstanceDataEvent";
+
+ public MultipleUserTaskInstanceDataEvent() {
+ }
+
+ public MultipleUserTaskInstanceDataEvent(URI source, Collection> body) {
+ super(TYPE, source, body);
+ }
+}
diff --git a/api/kogito-events-core/src/main/java/org/kie/kogito/event/usertask/UserTaskInstanceDataEvent.java b/api/kogito-events-core/src/main/java/org/kie/kogito/event/usertask/UserTaskInstanceDataEvent.java
index 98fc6528094..c4b3e0af5c9 100644
--- a/api/kogito-events-core/src/main/java/org/kie/kogito/event/usertask/UserTaskInstanceDataEvent.java
+++ b/api/kogito-events-core/src/main/java/org/kie/kogito/event/usertask/UserTaskInstanceDataEvent.java
@@ -18,6 +18,7 @@
*/
package org.kie.kogito.event.usertask;
+import java.net.URI;
import java.util.Set;
import org.kie.kogito.event.AbstractDataEvent;
@@ -48,6 +49,10 @@ public UserTaskInstanceDataEvent(T body) {
setData(body);
}
+ protected UserTaskInstanceDataEvent(String type, URI source, T body) {
+ super(type, source, body);
+ }
+
public UserTaskInstanceDataEvent(String type,
String source,
T body,
diff --git a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractNodeVisitor.java b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractNodeVisitor.java
index a8ce5a76b8d..1946318d05c 100644
--- a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractNodeVisitor.java
+++ b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractNodeVisitor.java
@@ -53,7 +53,6 @@
import org.jbpm.workflow.core.impl.ExtendedNodeImpl;
import org.jbpm.workflow.core.impl.NodeImpl;
import org.jbpm.workflow.core.node.Assignment;
-import org.jbpm.workflow.core.node.HumanTaskNode;
import org.jbpm.workflow.core.node.StartNode;
import org.jbpm.workflow.core.node.Transformation;
import org.kie.api.definition.process.Connection;
@@ -117,7 +116,7 @@ public ReturnValueEvaluatorBuilderService getReturnValueEvaluatorBuilderService(
public void visitNode(T node, BlockStmt body, VariableScope variableScope, ProcessMetaData metadata) {
visitNode(FACTORY_FIELD_NAME, node, body, variableScope, metadata);
- if (isAdHocNode(node) && !(node instanceof HumanTaskNode)) {
+ if (isAdHocNode(node)) {
metadata.addSignal(node.getName(), null);
}
if (isExtendedNode(node)) {
diff --git a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/ProcessToExecModelGenerator.java b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/ProcessToExecModelGenerator.java
index 253d24a7f0a..678c4657330 100644
--- a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/ProcessToExecModelGenerator.java
+++ b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/ProcessToExecModelGenerator.java
@@ -29,7 +29,7 @@
import org.jbpm.process.core.context.variable.Variable;
import org.jbpm.process.core.context.variable.VariableScope;
import org.jbpm.workflow.core.impl.WorkflowProcessImpl;
-import org.jbpm.workflow.core.node.HumanTaskNode;
+import org.jbpm.workflow.core.node.WorkItemNode;
import org.kie.api.definition.process.Node;
import org.kie.api.definition.process.WorkflowProcess;
import org.kie.kogito.ProcessInput;
@@ -243,27 +243,26 @@ public static String extractModelClassName(String processId) {
return sanitizeClassName(extractProcessId(processId) + MODEL_CLASS_SUFFIX);
}
- public List generateUserTaskModel(WorkflowProcess process) {
+ public List generateWorkItemModel(WorkflowProcess process) {
String packageName = process.getPackageName();
- List userTaskModels = new ArrayList<>();
+ List workItemTaskModels = new ArrayList<>();
VariableScope variableScope = (VariableScope) ((org.jbpm.process.core.Process) process).getDefaultContext(
VariableScope.VARIABLE_SCOPE);
for (Node node : ((WorkflowProcessImpl) process).getNodesRecursively()) {
- if (node instanceof HumanTaskNode) {
- HumanTaskNode humanTaskNode = (HumanTaskNode) node;
- VariableScope nodeVariableScope = (VariableScope) ((ContextContainer) humanTaskNode
+ if (node instanceof WorkItemNode workItemNode) {
+ VariableScope nodeVariableScope = (VariableScope) ((ContextContainer) workItemNode
.getParentContainer()).getDefaultContext(VariableScope.VARIABLE_SCOPE);
if (nodeVariableScope == null) {
nodeVariableScope = variableScope;
}
- userTaskModels.add(new UserTaskModelMetaData(packageName, variableScope, nodeVariableScope,
- humanTaskNode, process.getId()));
+ workItemTaskModels.add(new WorkItemModelMetaData(packageName, variableScope, nodeVariableScope,
+ workItemNode, process.getId()));
}
}
- return userTaskModels;
+ return workItemTaskModels;
}
public static String extractProcessId(String processId) {
diff --git a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/UserTaskModelMetaData.java b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/WorkItemModelMetaData.java
similarity index 90%
rename from jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/UserTaskModelMetaData.java
rename to jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/WorkItemModelMetaData.java
index 3d648ad2e2f..5ae74187907 100644
--- a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/UserTaskModelMetaData.java
+++ b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/WorkItemModelMetaData.java
@@ -30,7 +30,7 @@
import org.jbpm.process.core.datatype.DataType;
import org.jbpm.process.core.datatype.DataTypeResolver;
import org.jbpm.util.PatternConstants;
-import org.jbpm.workflow.core.node.HumanTaskNode;
+import org.jbpm.workflow.core.node.WorkItemNode;
import org.kie.api.definition.process.WorkflowElementIdentifier;
import org.kie.kogito.UserTask;
import org.kie.kogito.UserTaskParam;
@@ -70,7 +70,7 @@
import static org.jbpm.ruleflow.core.Metadata.CUSTOM_AUTO_START;
import static org.kie.kogito.internal.utils.ConversionUtils.sanitizeClassName;
-public class UserTaskModelMetaData {
+public class WorkItemModelMetaData {
private static final String TASK_INTPUT_CLASS_SUFFIX = "TaskInput";
private static final String TASK_OUTTPUT_CLASS_SUFFIX = "TaskOutput";
@@ -86,7 +86,7 @@ public class UserTaskModelMetaData {
private final VariableScope processVariableScope;
private final VariableScope variableScope;
- private final HumanTaskNode humanTaskNode;
+ private final WorkItemNode workItemNode;
private final String processId;
private String inputModelClassName;
@@ -98,20 +98,20 @@ public class UserTaskModelMetaData {
private String taskModelClassName;
private String taskModelClassSimpleName;
- public UserTaskModelMetaData(String packageName, VariableScope processVariableScope, VariableScope variableScope, HumanTaskNode humanTaskNode, String processId) {
+ public WorkItemModelMetaData(String packageName, VariableScope processVariableScope, VariableScope variableScope, WorkItemNode workItemNode, String processId) {
this.packageName = packageName;
this.processVariableScope = processVariableScope;
this.variableScope = variableScope;
- this.humanTaskNode = humanTaskNode;
+ this.workItemNode = workItemNode;
this.processId = processId;
- this.inputModelClassSimpleName = sanitizeClassName(ProcessToExecModelGenerator.extractProcessId(processId) + "_" + humanTaskNode.getId().toExternalFormat() + "_" + TASK_INTPUT_CLASS_SUFFIX);
+ this.inputModelClassSimpleName = sanitizeClassName(ProcessToExecModelGenerator.extractProcessId(processId) + "_" + workItemNode.getId().toExternalFormat() + "_" + TASK_INTPUT_CLASS_SUFFIX);
this.inputModelClassName = packageName + '.' + inputModelClassSimpleName;
- this.outputModelClassSimpleName = sanitizeClassName(ProcessToExecModelGenerator.extractProcessId(processId) + "_" + humanTaskNode.getId().toExternalFormat() + "_" + TASK_OUTTPUT_CLASS_SUFFIX);
+ this.outputModelClassSimpleName = sanitizeClassName(ProcessToExecModelGenerator.extractProcessId(processId) + "_" + workItemNode.getId().toExternalFormat() + "_" + TASK_OUTTPUT_CLASS_SUFFIX);
this.outputModelClassName = packageName + '.' + outputModelClassSimpleName;
- this.taskModelClassSimpleName = sanitizeClassName(ProcessToExecModelGenerator.extractProcessId(processId) + "_" + humanTaskNode.getId().toExternalFormat() + "_" + TASK_MODEL_CLASS_SUFFIX);
+ this.taskModelClassSimpleName = sanitizeClassName(ProcessToExecModelGenerator.extractProcessId(processId) + "_" + workItemNode.getId().toExternalFormat() + "_" + TASK_MODEL_CLASS_SUFFIX);
this.taskModelClassName = packageName + '.' + taskModelClassSimpleName;
}
@@ -144,21 +144,21 @@ public String getTaskModelClassName() {
}
public String getName() {
- return (String) humanTaskNode.getWork().getParameters().getOrDefault(TASK_NAME, humanTaskNode.getName());
+ return (String) workItemNode.getWork().getParameters().getOrDefault(TASK_NAME, workItemNode.getName());
}
public String getNodeName() {
- return humanTaskNode.getName();
+ return workItemNode.getName();
}
public WorkflowElementIdentifier getId() {
- return humanTaskNode.getId();
+ return workItemNode.getId();
}
private void addUserTaskAnnotation(ClassOrInterfaceDeclaration modelClass) {
- String taskName = (String) humanTaskNode.getWork().getParameter(TASK_NAME);
+ String taskName = (String) workItemNode.getWork().getParameter(TASK_NAME);
if (taskName == null)
- taskName = humanTaskNode.getName();
+ taskName = workItemNode.getName();
modelClass.addAndGetAnnotation(UserTask.class).addPair("taskName", new StringLiteralExpr(taskName)).addPair("processName", new StringLiteralExpr(processId));
}
@@ -190,8 +190,8 @@ private CompilationUnit compilationUnitInput() {
NameExpr item = new NameExpr("item");
// map is task input -> context variable / process variable
- Map inputTypes = humanTaskNode.getIoSpecification().getInputTypes();
- for (Entry entry : humanTaskNode.getIoSpecification().getInputMapping().entrySet()) {
+ Map inputTypes = workItemNode.getIoSpecification().getInputTypes();
+ for (Entry entry : workItemNode.getIoSpecification().getInputMapping().entrySet()) {
if (INTERNAL_FIELDS.contains(entry.getKey())) {
continue;
}
@@ -235,7 +235,7 @@ private CompilationUnit compilationUnitInput() {
AssignExpr.Operator.ASSIGN));
}
- for (Entry entry : humanTaskNode.getWork().getParameters().entrySet()) {
+ for (Entry entry : workItemNode.getWork().getParameters().entrySet()) {
if (entry.getValue() == null || INTERNAL_FIELDS.contains(entry.getKey())) {
continue;
@@ -275,7 +275,6 @@ private CompilationUnit compilationUnitInput() {
return compilationUnit;
}
- @SuppressWarnings({ "unchecked" })
private CompilationUnit compilationUnitOutput() {
CompilationUnit compilationUnit = parse(this.getClass().getResourceAsStream("/class-templates/TaskOutputTemplate.java"));
compilationUnit.setPackageDeclaration(packageName);
@@ -303,8 +302,8 @@ private CompilationUnit compilationUnitOutput() {
HashMap.class.getSimpleName() + "<>"), NodeList.nodeList()), AssignExpr.Operator.ASSIGN));
// map is task output -> context variable / process variable
- Map outputTypes = humanTaskNode.getIoSpecification().getOutputTypes();
- for (Entry entry : humanTaskNode.getIoSpecification().getOutputMappingBySources().entrySet()) {
+ Map outputTypes = workItemNode.getIoSpecification().getOutputTypes();
+ for (Entry entry : workItemNode.getIoSpecification().getOutputMappingBySources().entrySet()) {
if (entry.getValue() == null || INTERNAL_FIELDS.contains(entry.getKey())) {
continue;
}
@@ -382,7 +381,7 @@ private CompilationUnit compilationUnitModel() {
}
private void addComment(CompilationUnit unit, String prefix) {
- unit.addOrphanComment(new LineComment(prefix + " for user task '" + humanTaskNode.getName() + "' in process '" + processId + "'"));
+ unit.addOrphanComment(new LineComment(prefix + " for user task '" + workItemNode.getName() + "' in process '" + processId + "'"));
}
private void templateReplacement(NameExpr name) {
@@ -407,13 +406,13 @@ public String templateReplacement(String template) {
}
public boolean isAdHoc() {
- return !Boolean.parseBoolean((String) humanTaskNode.getMetaData(CUSTOM_AUTO_START))
- && (humanTaskNode.getIncomingConnections() == null || humanTaskNode.getIncomingConnections().isEmpty());
+ return !Boolean.parseBoolean((String) workItemNode.getMetaData(CUSTOM_AUTO_START))
+ && (workItemNode.getIncomingConnections() == null || workItemNode.getIncomingConnections().isEmpty());
}
public SwitchEntry getModelSwitchEntry() {
SwitchEntry entry = new SwitchEntry();
- entry.setLabels(NodeList.nodeList(new StringLiteralExpr(humanTaskNode.getId().toExternalFormat())));
+ entry.setLabels(NodeList.nodeList(new StringLiteralExpr(workItemNode.getId().toExternalFormat())));
entry.addStatement(new ReturnStmt(new MethodCallExpr(new NameExpr(
taskModelClassSimpleName), new SimpleName("from")).addArgument(WORK_ITEM)));
return entry;
diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/LightWorkItemManager.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/LightWorkItemManager.java
index 16a1519fe48..01b24104652 100755
--- a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/LightWorkItemManager.java
+++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/LightWorkItemManager.java
@@ -74,8 +74,12 @@ public void internalAddWorkItem(InternalKogitoWorkItem workItem) {
}
@Override
- public InternalKogitoWorkItem getWorkItem(String id) {
- return workItems.get(id);
+ public InternalKogitoWorkItem getWorkItem(String workItemId) {
+ InternalKogitoWorkItem workItem = workItems.get(workItemId);
+ if (workItem == null) {
+ throw new WorkItemNotFoundException("Work Item (" + workItemId + ") does not exist", workItemId);
+ }
+ return workItem;
}
@Override
@@ -131,7 +135,6 @@ public void retryWorkItem(String workItemId, Map params) {
KogitoWorkItemHandler handler = getWorkItemHandler(workItem);
WorkItemTransition transition = handler.startingTransition(Collections.emptyMap());
transitionWorkItem(workItem, transition, true);
-
}
@Override
@@ -143,7 +146,6 @@ public void completeWorkItem(String workItemId, Map data, Policy
KogitoProcessInstance processInstance = processInstanceManager.getProcessInstance(workItem.getProcessInstanceStringId());
workItem.setState(KogitoWorkItem.COMPLETED);
processInstance.signalEvent("workItemCompleted", workItem);
-
}
@Override
@@ -160,10 +162,7 @@ public void abortWorkItem(String workItemId, Policy... policies) {
@Override
public T updateWorkItem(String workItemId, Function updater, Policy... policies) {
- InternalKogitoWorkItem workItem = workItems.get(workItemId);
- if (workItem == null) {
- throw new WorkItemNotFoundException(workItemId);
- }
+ InternalKogitoWorkItem workItem = getWorkItem(workItemId);
Stream.of(policies).forEach(p -> p.enforce(workItem));
T results = updater.apply(workItem);
return results;
@@ -178,10 +177,7 @@ public void internalCompleteWorkItem(InternalKogitoWorkItem workItem) {
@Override
public void transitionWorkItem(String workItemId, WorkItemTransition transition) {
- InternalKogitoWorkItem workItem = workItems.get(workItemId);
- if (workItem == null) {
- throw new WorkItemNotFoundException("Work Item (" + workItemId + ") does not exist", workItemId);
- }
+ InternalKogitoWorkItem workItem = getWorkItem(workItemId);
transitionWorkItem(workItem, transition, true);
}
@@ -209,7 +205,7 @@ private void transitionWorkItem(InternalKogitoWorkItem workItem, WorkItemTransit
}
if (lastTransition.termination().isPresent()) {
- internalRemoveWorkItem(workItem.getStringId());
+
if (signal) {
switch (lastTransition.termination().get()) {
case COMPLETE:
@@ -222,6 +218,7 @@ private void transitionWorkItem(InternalKogitoWorkItem workItem, WorkItemTransit
break;
}
}
+
}
}
diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/CodegenNodeInstanceFactoryRegistry.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/CodegenNodeInstanceFactoryRegistry.java
index e7c89eda05c..a3dd4f5f391 100644
--- a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/CodegenNodeInstanceFactoryRegistry.java
+++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/CodegenNodeInstanceFactoryRegistry.java
@@ -24,11 +24,7 @@
public class CodegenNodeInstanceFactoryRegistry extends NodeInstanceFactoryRegistry {
- @Override
- protected NodeInstanceFactory get(Class> clazz) {
- if (SubProcessNode.class == clazz) {
- return new DefaultNodeInstanceFactory(SubProcessNode.class, LambdaSubProcessNodeInstance::new);
- }
- return super.get(clazz);
+ public CodegenNodeInstanceFactoryRegistry() {
+ register(SubProcessNode.class, new DefaultNodeInstanceFactory(SubProcessNode.class, LambdaSubProcessNodeInstance::new));
}
}
diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
index 7ae6edf3fb1..93554930fa8 100755
--- a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
+++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
@@ -76,6 +76,7 @@
import org.jbpm.workflow.instance.node.EventSubProcessNodeInstance;
import org.jbpm.workflow.instance.node.FaultNodeInstance;
import org.jbpm.workflow.instance.node.StateBasedNodeInstance;
+import org.jbpm.workflow.instance.node.WorkItemNodeInstance;
import org.kie.api.definition.process.NodeContainer;
import org.kie.api.definition.process.WorkflowElementIdentifier;
import org.kie.api.runtime.rule.AgendaFilter;
@@ -464,6 +465,11 @@ public void setState(final int state) {
@Override
public void disconnect() {
+ for (org.kie.api.runtime.process.NodeInstance nodeInstance : getNodeInstances(true)) {
+ if (nodeInstance instanceof WorkItemNodeInstance workItemNodeInstance) {
+ workItemNodeInstance.internalRemoveWorkItem();
+ }
+ }
removeEventListeners();
unregisterExternalEventNodeListeners();
@@ -478,11 +484,17 @@ public void disconnect() {
@Override
public void reconnect() {
super.reconnect();
+ for (org.kie.api.runtime.process.NodeInstance nodeInstance : getNodeInstances(true)) {
+ if (nodeInstance instanceof WorkItemNodeInstance workItemNodeInstance) {
+ workItemNodeInstance.internalRegisterWorkItem();
+ }
+ }
for (NodeInstance nodeInstance : nodeInstances) {
if (nodeInstance instanceof EventBasedNodeInstanceInterface) {
((EventBasedNodeInstanceInterface) nodeInstance).addEventListeners();
}
}
+
registerExternalEventNodeListeners();
}
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 5af0a5de03c..be1ff4ddfab 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
@@ -274,7 +274,7 @@ public void triggerCompleted(InternalKogitoWorkItem workItem) {
if (workItemNode != null && workItem.getState() == COMPLETED) {
validateWorkItemResultVariable(getProcessInstance().getProcessName(), workItemNode.getOutAssociations(), workItem);
Map outputs = new HashMap<>(workItem.getResults());
- if (workItem.getActualOwner() != null) {
+ if (workItem.getActualOwner() != null && !outputs.containsKey("ActorId")) {
outputs.put("ActorId", workItem.getActualOwner());
}
NodeIoHelper.processOutputs(this, varRef -> outputs.get(varRef), varName -> this.getVariable(varName));
@@ -284,6 +284,8 @@ public void triggerCompleted(InternalKogitoWorkItem workItem) {
setMetaData("NodeType", workItem.getName());
mapDynamicOutputData(workItem.getResults());
}
+
+ internalRemoveWorkItem();
if (isInversionOfControl()) {
KieRuntime kruntime = getProcessInstance().getKnowledgeRuntime();
kruntime.update(kruntime.getFactHandle(this), this);
diff --git a/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcessInstance.java b/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcessInstance.java
index 39d29374656..99f32900da2 100644
--- a/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcessInstance.java
+++ b/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcessInstance.java
@@ -73,9 +73,13 @@
import org.kie.kogito.process.flexible.Milestone;
import org.kie.kogito.process.workitems.InternalKogitoWorkItem;
import org.kie.kogito.services.uow.ProcessInstanceWorkUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public abstract class AbstractProcessInstance implements ProcessInstance {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractProcessInstance.class);
+
private static final String KOGITO_PROCESS_INSTANCE = "KogitoProcessInstance";
protected final T variables;
@@ -156,6 +160,7 @@ public AbstractProcessInstance(AbstractProcess process, T variables, ProcessR
}
protected void reconnect() {
+ LOG.debug("reconnect process {}", processInstance.getId());
//set correlation
if (correlationInstance.isEmpty()) {
correlationInstance = process().correlations().findByCorrelatedId(id());
@@ -169,12 +174,6 @@ protected void reconnect() {
processInstance.setMetaData(KOGITO_PROCESS_INSTANCE, this);
addCompletionEventListener();
- for (org.kie.api.runtime.process.NodeInstance nodeInstance : processInstance.getNodeInstances()) {
- if (nodeInstance instanceof WorkItemNodeInstance) {
- ((WorkItemNodeInstance) nodeInstance).internalRegisterWorkItem();
- }
- }
-
unbind(variables, processInstance.getVariables());
}
@@ -193,15 +192,12 @@ private void removeCompletionListener() {
}
protected void disconnect() {
+
if (processInstance == null) {
return;
}
- for (org.kie.api.runtime.process.NodeInstance nodeInstance : processInstance.getNodeInstances()) {
- if (nodeInstance instanceof WorkItemNodeInstance) {
- ((WorkItemNodeInstance) nodeInstance).internalRemoveWorkItem();
- }
- }
+ LOG.debug("disconnect process {}", processInstance.getId());
processInstance.disconnect();
processInstance.setMetaData(KOGITO_PROCESS_INSTANCE, null);
@@ -248,6 +244,7 @@ public void internalRemoveProcessInstance(Consumer> r
if (processInstance.getKnowledgeRuntime() != null) {
disconnect();
}
+
processInstance = null;
}
@@ -337,7 +334,7 @@ public T variables() {
@Override
public int status() {
- return this.status;
+ return status;
}
@Override
@@ -556,12 +553,14 @@ private boolean enforce(KogitoWorkItem kogitoWorkItem, Policy... policies) {
@Override
public void completeWorkItem(String id, Map variables, Policy... policies) {
+ syncWorkItems();
getProcessRuntime().getKogitoProcessRuntime().getKogitoWorkItemManager().completeWorkItem(id, variables, policies);
removeOnFinish();
}
@Override
public R updateWorkItem(String id, Function updater, Policy... policies) {
+ syncWorkItems();
R result = getProcessRuntime().getKogitoProcessRuntime().getKogitoWorkItemManager().updateWorkItem(id, updater, policies);
addToUnitOfWork(pi -> ((MutableProcessInstances) process.instances()).update(pi.id(), pi));
return result;
@@ -569,16 +568,26 @@ public R updateWorkItem(String id, Function updater, Poli
@Override
public void abortWorkItem(String id, Policy... policies) {
+ syncWorkItems();
getProcessRuntime().getKogitoProcessRuntime().getKogitoWorkItemManager().abortWorkItem(id, policies);
removeOnFinish();
}
@Override
public void transitionWorkItem(String id, WorkItemTransition transition) {
+ syncWorkItems();
getProcessRuntime().getKogitoProcessRuntime().getKogitoWorkItemManager().transitionWorkItem(id, transition);
removeOnFinish();
}
+ private void syncWorkItems() {
+ for (org.kie.api.runtime.process.NodeInstance nodeInstance : processInstance().getNodeInstances(true)) {
+ if (nodeInstance instanceof WorkItemNodeInstance workItemNodeInstance) {
+ workItemNodeInstance.internalRegisterWorkItem();
+ }
+ }
+ }
+
@Override
public Set> events() {
return processInstance().getEventDescriptions();
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 4fb06024d3e..d612a692961 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,31 +18,27 @@
*/
package org.kie.kogito.jbpm.usertask.handler;
-import java.util.Map;
+import java.util.Collections;
import java.util.Optional;
import java.util.Set;
-import org.kie.kogito.auth.SecurityPolicy;
-import org.kie.kogito.internal.process.workitem.InvalidTransitionException;
+import org.kie.kogito.Application;
+import org.kie.kogito.auth.IdentityProviders;
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.UserTasks;
import org.kie.kogito.usertask.impl.DefaultUserTaskInstance;
+import org.kie.kogito.usertask.impl.lifecycle.DefaultUserTaskLifeCycle;
import static java.util.Collections.emptyMap;
import static java.util.Optional.ofNullable;
+import static org.kie.kogito.usertask.impl.lifecycle.DefaultUserTaskLifeCycle.PARAMETER_NOTIFY;
+import static org.kie.kogito.usertask.impl.lifecycle.DefaultUserTaskLifeCycle.WORKFLOW_ENGINE_USER;
/**
* Default Work Item handler based on the standard life cycle
@@ -51,29 +47,6 @@ 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_ACTIVATED_COMPLETE =
- new DefaultWorkItemLifeCyclePhase("complete", ACTIVATED, COMPLETED, UserTaskKogitoWorkItemHandler::userTaskCompleteFromActiveWorkItemHandler);
- public static final WorkItemLifeCyclePhase TRANSITION_RESERVED_ABORT =
- new DefaultWorkItemLifeCyclePhase("abort", RESERVED, ABORTED, UserTaskKogitoWorkItemHandler::userTaskAbortWorkItemHandler);
- public static final WorkItemLifeCyclePhase TRANSITION_ACTIVATED_ABORT =
- new DefaultWorkItemLifeCyclePhase("abort", ACTIVATED, 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);
- public static final WorkItemLifeCyclePhase TRANSITION_ACTIVATED_COMPLETED =
- new DefaultWorkItemLifeCyclePhase("skip", ACTIVATED, COMPLETED, UserTaskKogitoWorkItemHandler::userTaskCompleteWorkItemHandler);
-
private static final String DESCRIPTION = "Description";
private static final String PRIORITY = "Priority";
private static final String TASK_NAME = "TaskName";
@@ -83,40 +56,16 @@ public class UserTaskKogitoWorkItemHandler extends DefaultKogitoWorkItemHandler
private static final String BUSINESSADMINISTRATOR_GROUP_ID = "BusinessAdministratorGroupId";
private static final String EXCLUDED_OWNER_ID = "ExcludedOwnerId";
- @Override
- public String getName() {
- return "Human Task";
- }
-
- @Override
- public WorkItemLifeCycle initialize() {
- return new DefaultWorkItemLifeCycle(
- TRANSITION_CREATED_ACTIVE,
- TRANSITION_ACTIVATED_CLAIM,
- TRANSITION_ACTIVATED_ABORT,
- TRANSITION_ACTIVATED_COMPLETE,
- TRANSITION_RESERVED_RELEASE,
- TRANSITION_RESERVED_ABORT,
- TRANSITION_RESERVED_COMPLETE,
- TRANSITION_ACTIVATED_COMPLETED);
- }
-
- @Override
- public WorkItemTransition startingTransition(Map data, Policy... policies) {
- return workItemLifeCycle.newTransition("activate", null, data, policies);
- }
-
- @Override
- public WorkItemTransition abortTransition(String phaseStatus, Policy... policies) {
- return workItemLifeCycle.newTransition("abort", phaseStatus, emptyMap(), policies);
+ public UserTaskKogitoWorkItemHandler() {
+ super();
}
- @Override
- public WorkItemTransition completeTransition(String phaseStatus, Map data, Policy... policies) {
- return workItemLifeCycle.newTransition("complete", phaseStatus, data, policies);
+ public UserTaskKogitoWorkItemHandler(Application application) {
+ super();
+ this.setApplication(application);
}
- static public Optional userTaskActivateWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) {
+ public Optional activateWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) {
UserTasks userTasks = handler.getApplication().get(UserTasks.class);
Object priority = workItem.getParameter(PRIORITY);
@@ -130,11 +79,11 @@ static public Optional userTaskActivateWorkItemHandler(Kogit
UserTask userTask = userTasks.userTaskById((String) workItem.getParameter(KogitoWorkItem.PARAMETER_UNIQUE_TASK_ID));
DefaultUserTaskInstance instance = (DefaultUserTaskInstance) userTask.createInstance();
- instance.setId(workItem.getStringId());
instance.setTaskName((String) workItem.getParameter(TASK_NAME));
instance.setTaskDescription((String) workItem.getParameter(DESCRIPTION));
instance.setTaskPriority(priorityInteger);
instance.setExternalReferenceId(workItem.getStringId());
+
instance.setMetadata("ProcessId", workItem.getProcessInstance().getProcessId());
instance.setMetadata("ProcessType", workItem.getProcessInstance().getProcess().getType());
instance.setMetadata("ProcessVersion", workItem.getProcessInstance().getProcessVersion());
@@ -144,114 +93,61 @@ static public Optional userTaskActivateWorkItemHandler(Kogit
instance.setMetadata("RootProcessInstanceId", workItem.getProcessInstance().getRootProcessInstanceId());
instance.setMetadata("ParentProcessInstanceId", workItem.getProcessInstance().getParentProcessInstanceId());
- ofNullable(workItem.getParameters().get(ACTOR_ID)).map(String.class::cast).map(UserTaskKogitoWorkItemHandler::toSet).ifPresent(instance::setPotentialUsers);
- ofNullable(workItem.getParameters().get(GROUP_ID)).map(String.class::cast).map(UserTaskKogitoWorkItemHandler::toSet).ifPresent(instance::setPotentialGroups);
- ofNullable(workItem.getParameters().get(BUSINESSADMINISTRATOR_ID)).map(String.class::cast).map(UserTaskKogitoWorkItemHandler::toSet).ifPresent(instance::setAdminUsers);
- ofNullable(workItem.getParameters().get(BUSINESSADMINISTRATOR_GROUP_ID)).map(String.class::cast).map(UserTaskKogitoWorkItemHandler::toSet).ifPresent(instance::setAdminGroups);
- ofNullable(workItem.getParameters().get(EXCLUDED_OWNER_ID)).map(String.class::cast).map(UserTaskKogitoWorkItemHandler::toSet).ifPresent(instance::setExcludedUsers);
+ userTask.instances().create(instance);
+ instance.fireInitialStateChange();
+ workItem.getParameters().forEach(instance::setInput);
+
+ ofNullable(workItem.getParameters().get(ACTOR_ID)).map(String.class::cast).map(this::toSet).ifPresent(instance::setPotentialUsers);
+ ofNullable(workItem.getParameters().get(GROUP_ID)).map(String.class::cast).map(this::toSet).ifPresent(instance::setPotentialGroups);
+ ofNullable(workItem.getParameters().get(BUSINESSADMINISTRATOR_ID)).map(String.class::cast).map(this::toSet).ifPresent(instance::setAdminUsers);
+ ofNullable(workItem.getParameters().get(BUSINESSADMINISTRATOR_GROUP_ID)).map(String.class::cast).map(this::toSet).ifPresent(instance::setAdminGroups);
+ ofNullable(workItem.getParameters().get(EXCLUDED_OWNER_ID)).map(String.class::cast).map(this::toSet).ifPresent(instance::setExcludedUsers);
- instance.assign();
- instance.transition(instance.createTransitionToken("activate", emptyMap()));
+ instance.transition(DefaultUserTaskLifeCycle.ACTIVATE, emptyMap(), IdentityProviders.of(WORKFLOW_ENGINE_USER));
if (workItem instanceof InternalKogitoWorkItem ikw) {
ikw.setExternalReferenceId(instance.getId());
ikw.setActualOwner(instance.getActualOwner());
}
- userTask.instances().create(instance);
- return Optional.empty();
- }
- static protected Set toSet(String value) {
- if (value == null) {
- return null;
- }
- return Set.of(value.split(UT_SEPARATOR));
+ return Optional.empty();
}
- static public Optional userTaskClaimWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) {
- workItem.removeOutput("ACTUAL_OWNER");
-
+ @Override
+ public Optional completeWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) {
UserTasks userTasks = handler.getApplication().get(UserTasks.class);
UserTask userTask = userTasks.userTaskById((String) workItem.getParameter(KogitoWorkItem.PARAMETER_UNIQUE_TASK_ID));
userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(ut -> {
- Map data = transition.data();
if (workItem instanceof InternalKogitoWorkItem ikw) {
- getUserFromTransition(transition).ifPresent(ikw::setActualOwner);
- if (data.containsKey("ACTUAL_OWNER") && ikw.getActualOwner() == null) {
- ut.setActuaOwner((String) data.get("ACTUAL_OWNER"));
- }
- if (ikw.getActualOwner() == null) {
- throw new InvalidTransitionException("transition claim does not contain user id");
- }
+ ikw.setActualOwner(ut.getActualOwner());
}
- ut.setActuaOwner(workItem.getActualOwner());
- ut.transition(ut.createTransitionToken("claim", emptyMap()));
- userTask.instances().update(ut);
+ ut.transition(DefaultUserTaskLifeCycle.SKIP, Collections.singletonMap(PARAMETER_NOTIFY, Boolean.FALSE), IdentityProviders.of(WORKFLOW_ENGINE_USER));
});
return Optional.empty();
}
- static public Optional userTaskReleaseWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) {
- if (workItem instanceof InternalKogitoWorkItem ikw) {
- ikw.setActualOwner(null);
- }
- UserTasks userTasks = handler.getApplication().get(UserTasks.class);
- UserTask userTask = userTasks.userTaskById((String) workItem.getParameter(KogitoWorkItem.PARAMETER_UNIQUE_TASK_ID));
- userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(ut -> {
- ut.setActuaOwner(null);
- ut.transition(ut.createTransitionToken("release", emptyMap()));
- userTask.instances().update(ut);
- });
-
- return Optional.empty();
- }
-
- static public Optional userTaskCompleteWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) {
+ @Override
+ public Optional abortWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) {
UserTasks userTasks = handler.getApplication().get(UserTasks.class);
UserTask userTask = userTasks.userTaskById((String) workItem.getParameter(KogitoWorkItem.PARAMETER_UNIQUE_TASK_ID));
userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(ut -> {
- ut.transition(ut.createTransitionToken("complete", emptyMap()));
- userTask.instances().update(ut);
+ if (workItem instanceof InternalKogitoWorkItem ikw) {
+ ikw.setActualOwner(ut.getActualOwner());
+ }
+ ut.transition(DefaultUserTaskLifeCycle.FAIL, Collections.singletonMap(PARAMETER_NOTIFY, Boolean.FALSE), IdentityProviders.of(WORKFLOW_ENGINE_USER));
});
- if (workItem instanceof InternalKogitoWorkItem ikw && ikw.getActualOwner() == null) {
- getUserFromTransition(transition).ifPresent(user -> {
- ikw.setActualOwner(user);
- });
- }
return Optional.empty();
}
- static public Optional userTaskCompleteFromActiveWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem,
- WorkItemTransition transition) {
- UserTasks userTasks = handler.getApplication().get(UserTasks.class);
- UserTask userTask = userTasks.userTaskById((String) workItem.getParameter(KogitoWorkItem.PARAMETER_UNIQUE_TASK_ID));
- userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(ut -> {
- ut.transition(ut.createTransitionToken("complete", emptyMap()));
- userTask.instances().update(ut);
- });
- if (workItem instanceof InternalKogitoWorkItem ikw) {
- getUserFromTransition(transition).ifPresent(user -> {
- ikw.setActualOwner(user);
- });
+ protected Set toSet(String value) {
+ if (value == null) {
+ return null;
}
- return Optional.empty();
- }
-
- 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(KogitoWorkItem.PARAMETER_UNIQUE_TASK_ID));
- userTask.instances().findById(workItem.getExternalReferenceId()).ifPresent(ut -> {
- ut.transition(ut.createTransitionToken("skip", emptyMap()));
- userTask.instances().update(ut);
- });
- return Optional.empty();
+ return Set.of(value.split(UT_SEPARATOR));
}
- private static Optional getUserFromTransition(WorkItemTransition transition) {
- Optional securityPolicy = transition.policies().stream().filter(SecurityPolicy.class::isInstance).map(SecurityPolicy.class::cast).findAny();
- if (securityPolicy.isPresent()) {
- return Optional.ofNullable(securityPolicy.get().getUser());
- }
- return Optional.empty();
+ @Override
+ public String getName() {
+ return "Human Task";
}
}
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/jbpm/usertask/handler/UserTaskKogitoWorkItemHandlerProcessListener.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/jbpm/usertask/handler/UserTaskKogitoWorkItemHandlerProcessListener.java
new file mode 100644
index 00000000000..7d0bc70557a
--- /dev/null
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/jbpm/usertask/handler/UserTaskKogitoWorkItemHandlerProcessListener.java
@@ -0,0 +1,66 @@
+/*
+ * 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.jbpm.usertask.handler;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.kie.kogito.process.Processes;
+import org.kie.kogito.usertask.UserTaskEventListener;
+import org.kie.kogito.usertask.events.UserTaskStateEvent;
+import org.kie.kogito.usertask.impl.lifecycle.DefaultUserTaskLifeCycle;
+import org.kie.kogito.usertask.lifecycle.UserTaskState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UserTaskKogitoWorkItemHandlerProcessListener implements UserTaskEventListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(UserTaskKogitoWorkItemHandlerProcessListener.class);
+
+ private Processes processes;
+
+ public UserTaskKogitoWorkItemHandlerProcessListener(Processes processes) {
+ this.processes = processes;
+ }
+
+ @Override
+ public void onUserTaskState(UserTaskStateEvent event) {
+ UserTaskState userTaskState = event.getNewStatus();
+ if (!userTaskState.isTerminate()) {
+ return;
+ }
+
+ // we check first that the work item is not finished to convey the signal
+ Boolean notify = (Boolean) event.getUserTaskInstance().getMetadata().get(DefaultUserTaskLifeCycle.PARAMETER_NOTIFY);
+ if (notify != null && !notify) {
+ return;
+ }
+
+ LOG.debug("onUserTaskState {} on complete work item", event);
+ String processId = (String) event.getUserTaskInstance().getMetadata().get("ProcessId");
+ String processInstanceId = (String) event.getUserTaskInstance().getMetadata().get("ProcessInstanceId");
+
+ processes.processById(processId).instances().findById(processInstanceId).ifPresent(pi -> {
+ Map data = new HashMap<>(event.getUserTaskInstance().getOutputs());
+ data.put("ActorId", event.getUserTaskInstance().getActualOwner());
+ pi.completeWorkItem(event.getUserTaskInstance().getExternalReferenceId(), data);
+ });
+
+ }
+}
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/AbstractUserTask.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/AbstractUserTask.java
new file mode 100644
index 00000000000..19a7d8c1e74
--- /dev/null
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/AbstractUserTask.java
@@ -0,0 +1,248 @@
+/*
+ * 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;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.kie.kogito.usertask.UserTask;
+import org.kie.kogito.usertask.UserTaskInstance;
+import org.kie.kogito.usertask.impl.model.DeadlineHelper;
+import org.kie.kogito.usertask.model.DeadlineInfo;
+import org.kie.kogito.usertask.model.Reassignment;
+
+public abstract class AbstractUserTask implements UserTask {
+ private String separator = System.getProperty("org.jbpm.ht.user.separator", ",");
+
+ private String id;
+ private String name;
+ private String taskName;
+ private String taskDescription;
+ private String referenceName;
+ private Integer taskPriority;
+ private Boolean skippable;
+ private Set potentialUsers;
+ private Set potentialGroups;
+ private Set adminUsers;
+ private Set adminGroups;
+ private Set excludedUsers;
+ private Collection>> startDeadlines;
+ private Collection>> endDeadlines;
+ private Collection> startReassigments;
+ private Collection> endReassigments;
+
+ public AbstractUserTask(String id, String name) {
+ this.id = id;
+ this.name = name;
+ this.skippable = Boolean.FALSE;
+ this.potentialUsers = new HashSet<>();
+ this.potentialGroups = new HashSet<>();
+ this.adminUsers = new HashSet<>();
+ this.adminGroups = new HashSet<>();
+ this.excludedUsers = new HashSet<>();
+ this.startDeadlines = new HashSet<>();
+ this.endDeadlines = new HashSet<>();
+ this.startReassigments = new HashSet<>();
+ this.endReassigments = new HashSet<>();
+ }
+
+ @Override
+ public UserTaskInstance createInstance() {
+ DefaultUserTaskInstance instance = new DefaultUserTaskInstance(this);
+ instance.setUserTaskId(id());
+ instance.setTaskName(getTaskName());
+ instance.setTaskDescription(getTaskDescription());
+ instance.setTaskPriority(getTaskPriority());
+ instance.setPotentialUsers(getPotentialUsers());
+ instance.setPotentialGroups(getPotentialGroups());
+ instance.setAdminUsers(getAdminUsers());
+ instance.setPotentialGroups(getPotentialGroups());
+ instance.setExcludedUsers(getExcludedUsers());
+ return instance;
+ }
+
+ @Override
+ public String id() {
+ return id;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ public void setSkippable(String skippable) {
+ this.skippable = Boolean.parseBoolean(skippable);
+ }
+
+ public Boolean getSkippable() {
+ return skippable;
+ }
+
+ @Override
+ public String getTaskName() {
+ return taskName;
+ }
+
+ public void setTaskName(String taskName) {
+ this.taskName = taskName;
+ }
+
+ @Override
+ public String getTaskDescription() {
+ return taskDescription;
+ }
+
+ public void setTaskDescription(String taskDescription) {
+ this.taskDescription = taskDescription;
+ }
+
+ @Override
+ public Integer getTaskPriority() {
+ return this.taskPriority;
+ }
+
+ public void setTaskPriority(Integer taskPriority) {
+ this.taskPriority = taskPriority;
+ }
+
+ public void setReferenceName(String referenceName) {
+ this.referenceName = referenceName;
+ }
+
+ @Override
+ public String getReferenceName() {
+ return referenceName;
+ }
+
+ @Override
+ public Set getPotentialUsers() {
+ return this.potentialUsers;
+ }
+
+ public void setPotentialUsers(String potentialUsers) {
+ this.setPotentialUsers(toSet(potentialUsers));
+ }
+
+ public void setPotentialUsers(Set potentialUsers) {
+ this.potentialUsers = potentialUsers;
+ }
+
+ @Override
+ public Set getPotentialGroups() {
+ return this.potentialGroups;
+ }
+
+ public void setPotentialGroups(String potentialGroups) {
+ this.setPotentialGroups(toSet(potentialGroups));
+ }
+
+ public void setPotentialGroups(Set potentialGroups) {
+ this.potentialGroups = potentialGroups;
+ }
+
+ @Override
+ public Set getAdminUsers() {
+ return this.adminUsers;
+ }
+
+ public void setAdminUsers(String adminUsers) {
+ this.setAdminUsers(toSet(adminUsers));
+ }
+
+ public void setAdminUsers(Set adminUsers) {
+ this.adminUsers = adminUsers;
+ }
+
+ @Override
+ public Set getAdminGroups() {
+ return this.adminGroups;
+ }
+
+ public void setAdminGroups(String adminGroups) {
+ this.setAdminGroups(toSet(adminGroups));
+ }
+
+ public void setAdminGroups(Set adminGroups) {
+ this.adminGroups = adminGroups;
+ }
+
+ @Override
+ public Set getExcludedUsers() {
+ return this.excludedUsers;
+ }
+
+ public void setExcludedUsers(String excludedUsers) {
+ this.setExcludedUsers(toSet(excludedUsers));
+ }
+
+ public void setExcludedUsers(Set excludedUsers) {
+ this.excludedUsers = excludedUsers;
+ }
+
+ @Override
+ public Collection>> getNotStartedDeadlines() {
+ return startDeadlines;
+ }
+
+ public void setNotStartedDeadLines(String deadlines) {
+ this.startDeadlines = DeadlineHelper.parseDeadlines(deadlines);
+ }
+
+ @Override
+ public Collection>> getNotCompletedDeadlines() {
+ return endDeadlines;
+ }
+
+ public void setNotCompletedDeadlines(String notStarted) {
+ this.endDeadlines = DeadlineHelper.parseDeadlines(notStarted);
+ }
+
+ @Override
+ public Collection> getNotStartedReassignments() {
+ return startReassigments;
+ }
+
+ public void setNotStartedReassignments(String reassignments) {
+ this.startReassigments = DeadlineHelper.parseReassignments(reassignments);
+ }
+
+ @Override
+ public Collection> getNotCompletedReassigments() {
+ return endReassigments;
+ }
+
+ public void setNotCompletedReassigments(String reassignments) {
+ this.endReassigments = DeadlineHelper.parseReassignments(reassignments);
+ }
+
+ protected Set toSet(String value) {
+ if (value == null) {
+ return new HashSet<>();
+ }
+ Set store = new HashSet<>();
+ for (String item : value.split(separator)) {
+ store.add(item);
+ }
+ return store;
+ }
+
+}
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/BasicUserTaskAssignmentStrategy.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/BasicUserTaskAssignmentStrategy.java
new file mode 100644
index 00000000000..076a62c313e
--- /dev/null
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/BasicUserTaskAssignmentStrategy.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import org.kie.kogito.auth.IdentityProvider;
+import org.kie.kogito.usertask.UserTaskAssignmentStrategy;
+import org.kie.kogito.usertask.UserTaskInstance;
+
+public class BasicUserTaskAssignmentStrategy implements UserTaskAssignmentStrategy {
+
+ @Override
+ public String getName() {
+ return DEFAULT_NAME;
+ }
+
+ @Override
+ public Optional computeAssigment(UserTaskInstance userTaskInstance, IdentityProvider identityProvider) {
+ Set users = new HashSet<>(userTaskInstance.getPotentialUsers());
+ users.removeAll(userTaskInstance.getExcludedUsers());
+ if (users.size() == 1) {
+ return Optional.of(users.iterator().next());
+ }
+ 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 92e2fa9c745..9b80e6e7176 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
@@ -18,115 +18,30 @@
*/
package org.kie.kogito.usertask.impl;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
import org.kie.kogito.Application;
-import org.kie.kogito.uow.events.UnitOfWorkUserTaskEventListener;
-import org.kie.kogito.usertask.UserTask;
+import org.kie.kogito.usertask.UserTaskAssignmentStrategy;
import org.kie.kogito.usertask.UserTaskConfig;
-import org.kie.kogito.usertask.UserTaskInstance;
import org.kie.kogito.usertask.UserTaskInstances;
-import org.kie.kogito.usertask.impl.model.DeadlineHelper;
-import org.kie.kogito.usertask.model.DeadlineInfo;
-import org.kie.kogito.usertask.model.Reassignment;
-
-public class DefaultUserTask implements UserTask {
- private String separator = System.getProperty("org.jbpm.ht.user.separator", ",");
+public class DefaultUserTask extends AbstractUserTask {
private Application application;
- private String id;
private UserTaskInstances userTaskInstances;
- private String name;
- private String taskName;
- private String taskDescription;
- private String referenceName;
- private Integer taskPriority;
- private Boolean skippable;
- private Set potentialUsers;
- private Set potentialGroups;
- private Set adminUsers;
- private Set adminGroups;
- private Set excludedUsers;
- private Collection>> startDeadlines;
- private Collection>> endDeadlines;
- private Collection> startReassigments;
- private Collection> endReassigments;
-
- public DefaultUserTask() {
- // nothing
- }
public DefaultUserTask(String id, String name) {
- this(null, id, name, new InMemoryUserTaskInstances());
+ super(id, name);
}
public DefaultUserTask(Application application, String id, String name) {
- this(application, id, name, new InMemoryUserTaskInstances());
- }
-
- public DefaultUserTask(Application application, String id, String name, UserTaskInstances userTaskInstances) {
- this.application = application;
- this.id = id;
- this.name = name;
- this.userTaskInstances = userTaskInstances;
- this.userTaskInstances.setReconnectUserTaskInstance(this::connect);
- this.userTaskInstances.setDisconnectUserTaskInstance(this::disconnect);
- this.skippable = Boolean.FALSE;
- this.potentialUsers = new HashSet<>();
- this.potentialGroups = new HashSet<>();
- this.adminUsers = new HashSet<>();
- this.adminGroups = new HashSet<>();
- this.excludedUsers = new HashSet<>();
- this.startDeadlines = new HashSet<>();
- this.endDeadlines = new HashSet<>();
- this.startReassigments = new HashSet<>();
- this.endReassigments = new HashSet<>();
-
- }
-
- public void setApplication(Application application) {
+ super(id, name);
this.application = application;
+ this.userTaskInstances = application.config().get(UserTaskConfig.class).userTaskInstances();
}
@Override
- public UserTaskInstance createInstance() {
- DefaultUserTaskInstance instance = new DefaultUserTaskInstance(this);
- instance.setTaskName(getTaskName());
- instance.setTaskDescription(getTaskDescription());
- instance.setTaskPriority(getTaskPriority());
- instance.setPotentialUsers(getPotentialUsers());
- instance.setPotentialGroups(getPotentialGroups());
- instance.setAdminUsers(getAdminUsers());
- instance.setPotentialGroups(getPotentialGroups());
- instance.setExcludedUsers(getExcludedUsers());
- connect(instance);
- return instance;
- }
-
- private UserTaskInstance disconnect(UserTaskInstance userTaskInstance) {
- DefaultUserTaskInstance instance = (DefaultUserTaskInstance) userTaskInstance;
- instance.setUserTask(null);
- instance.setUserTaskEventSupport(null);
- instance.setUserTaskLifeCycle(null);
- instance.setInstances(null);
- return instance;
- }
-
- public UserTaskInstance connect(UserTaskInstance userTaskInstance) {
- DefaultUserTaskInstance instance = (DefaultUserTaskInstance) userTaskInstance;
+ public UserTaskAssignmentStrategy getAssignmentStrategy() {
UserTaskConfig userTaskConfig = application.config().get(UserTaskConfig.class);
- KogitoUserTaskEventSupportImpl impl = new KogitoUserTaskEventSupportImpl(userTaskConfig.identityProvider());
- userTaskConfig.userTaskEventListeners().listeners().forEach(impl::addEventListener);
- impl.addEventListener(new UnitOfWorkUserTaskEventListener(application.unitOfWorkManager()));
- instance.setUserTask(this);
- instance.setUserTaskEventSupport(impl);
- instance.setUserTaskLifeCycle(userTaskConfig.userTaskLifeCycle());
- instance.setInstances(userTaskInstances);
- return instance;
+ return userTaskConfig.userTaskAssignmentStrategies().defaultUserTaskAssignmentStrategy();
}
@Override
@@ -134,170 +49,4 @@ public UserTaskInstances instances() {
return userTaskInstances;
}
- @Override
- public String id() {
- return id;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- public void setSkippable(String skippable) {
- this.skippable = Boolean.parseBoolean(skippable);
- }
-
- public Boolean getSkippable() {
- return skippable;
- }
-
- @Override
- public String getTaskName() {
- return taskName;
- }
-
- public void setTaskName(String taskName) {
- this.taskName = taskName;
- }
-
- @Override
- public String getTaskDescription() {
- return taskDescription;
- }
-
- public void setTaskDescription(String taskDescription) {
- this.taskDescription = taskDescription;
- }
-
- @Override
- public Integer getTaskPriority() {
- return this.taskPriority;
- }
-
- public void setTaskPriority(Integer taskPriority) {
- this.taskPriority = taskPriority;
- }
-
- public void setReferenceName(String referenceName) {
- this.referenceName = referenceName;
- }
-
- @Override
- public String getReferenceName() {
- return referenceName;
- }
-
- @Override
- public Set getPotentialUsers() {
- return this.potentialUsers;
- }
-
- public void setPotentialUsers(String potentialUsers) {
- this.setPotentialUsers(toSet(potentialUsers));
- }
-
- public void setPotentialUsers(Set potentialUsers) {
- this.potentialUsers = potentialUsers;
- }
-
- @Override
- public Set getPotentialGroups() {
- return this.potentialGroups;
- }
-
- public void setPotentialGroups(String potentialGroups) {
- this.setPotentialGroups(toSet(potentialGroups));
- }
-
- public void setPotentialGroups(Set potentialGroups) {
- this.potentialGroups = potentialGroups;
- }
-
- @Override
- public Set getAdminUsers() {
- return this.adminUsers;
- }
-
- public void setAdminUsers(String adminUsers) {
- this.setAdminUsers(toSet(adminUsers));
- }
-
- public void setAdminUsers(Set adminUsers) {
- this.adminUsers = adminUsers;
- }
-
- @Override
- public Set getAdminGroups() {
- return this.adminGroups;
- }
-
- public void setAdminGroups(String adminGroups) {
- this.setAdminGroups(toSet(adminGroups));
- }
-
- public void setAdminGroups(Set adminGroups) {
- this.adminGroups = adminGroups;
- }
-
- @Override
- public Set getExcludedUsers() {
- return this.excludedUsers;
- }
-
- public void setExcludedUsers(String excludedUsers) {
- this.setExcludedUsers(toSet(excludedUsers));
- }
-
- public void setExcludedUsers(Set excludedUsers) {
- this.excludedUsers = excludedUsers;
- }
-
- @Override
- public Collection>> getNotStartedDeadlines() {
- return startDeadlines;
- }
-
- public void setNotStartedDeadLines(String deadlines) {
- this.startDeadlines = DeadlineHelper.parseDeadlines(deadlines);
- }
-
- @Override
- public Collection>> getNotCompletedDeadlines() {
- return endDeadlines;
- }
-
- public void setNotCompletedDeadlines(String notStarted) {
- this.endDeadlines = DeadlineHelper.parseDeadlines(notStarted);
- }
-
- @Override
- public Collection> getNotStartedReassignments() {
- return startReassigments;
- }
-
- public void setNotStartedReassignments(String reassignments) {
- this.startReassigments = DeadlineHelper.parseReassignments(reassignments);
- }
-
- @Override
- public Collection> getNotCompletedReassigments() {
- return endReassigments;
- }
-
- public void setNotCompletedReassigments(String reassignments) {
- this.endReassigments = DeadlineHelper.parseReassignments(reassignments);
- }
-
- protected Set toSet(String value) {
- if (value == null) {
- return new HashSet<>();
- }
- Set store = new HashSet<>();
- for (String item : value.split(separator)) {
- store.add(item);
- }
- return store;
- }
-
}
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskAssignmentStrategyConfig.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskAssignmentStrategyConfig.java
new file mode 100644
index 00000000000..5c6029b4778
--- /dev/null
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskAssignmentStrategyConfig.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.kie.kogito.usertask.UserTaskAssignmentStrategy;
+import org.kie.kogito.usertask.UserTaskAssignmentStrategyConfig;
+
+public class DefaultUserTaskAssignmentStrategyConfig implements UserTaskAssignmentStrategyConfig {
+
+ private Map userTaskAssignmentStrategies;
+
+ public DefaultUserTaskAssignmentStrategyConfig() {
+ this.userTaskAssignmentStrategies = new HashMap<>();
+ BasicUserTaskAssignmentStrategy strategy = new BasicUserTaskAssignmentStrategy();
+ this.userTaskAssignmentStrategies.put(strategy.getName(), strategy);
+ }
+
+ public DefaultUserTaskAssignmentStrategyConfig(Iterable userTaskAssignmentStrategies) {
+ this();
+ userTaskAssignmentStrategies.forEach(uts -> this.userTaskAssignmentStrategies.put(uts.getName(), uts));
+ }
+
+ @Override
+ public List userTaskAssignmentStrategies() {
+ return new ArrayList<>(userTaskAssignmentStrategies.values());
+ }
+
+ @Override
+ public UserTaskAssignmentStrategy forName(String name) {
+ return userTaskAssignmentStrategies.get(name);
+ }
+
+}
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskConfig.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskConfig.java
index 93d012f0116..7282ce72532 100644
--- a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskConfig.java
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskConfig.java
@@ -27,8 +27,10 @@
import org.kie.kogito.services.uow.CollectingUnitOfWorkFactory;
import org.kie.kogito.services.uow.DefaultUnitOfWorkManager;
import org.kie.kogito.uow.UnitOfWorkManager;
+import org.kie.kogito.usertask.UserTaskAssignmentStrategyConfig;
import org.kie.kogito.usertask.UserTaskConfig;
import org.kie.kogito.usertask.UserTaskEventListenerConfig;
+import org.kie.kogito.usertask.UserTaskInstances;
import org.kie.kogito.usertask.impl.lifecycle.DefaultUserTaskLifeCycle;
import org.kie.kogito.usertask.lifecycle.UserTaskLifeCycle;
@@ -39,13 +41,17 @@ public class DefaultUserTaskConfig implements UserTaskConfig {
private JobsService jobService;
private IdentityProvider identityProvider;
private UserTaskLifeCycle userTaskLifeCycle;
+ private UserTaskAssignmentStrategyConfig userTaskAssignmentStrategyConfig;
+ private UserTaskInstances userTaskInstances;
public DefaultUserTaskConfig() {
this(new DefaultUserTaskEventListenerConfig(),
new DefaultUnitOfWorkManager(new CollectingUnitOfWorkFactory()),
null,
new NoOpIdentityProvider(),
- new DefaultUserTaskLifeCycle());
+ new DefaultUserTaskLifeCycle(),
+ new DefaultUserTaskAssignmentStrategyConfig(),
+ new InMemoryUserTaskInstances());
}
public DefaultUserTaskConfig(
@@ -53,13 +59,17 @@ public DefaultUserTaskConfig(
Iterable unitOfWorkManager,
Iterable jobService,
Iterable identityProvider,
- Iterable userTaskLifeCycle) {
+ Iterable userTaskLifeCycle,
+ Iterable userTaskAssignmentStrategyConfig,
+ Iterable userTaskInstances) {
this.userTaskEventListeners = singleton(userTaskEventListenerConfig, DefaultUserTaskEventListenerConfig::new);
this.unitOfWorkManager = singleton(unitOfWorkManager, () -> new DefaultUnitOfWorkManager(new CollectingUnitOfWorkFactory()));
this.jobService = singleton(jobService, () -> null);
this.identityProvider = singleton(identityProvider, NoOpIdentityProvider::new);
this.userTaskLifeCycle = singleton(userTaskLifeCycle, DefaultUserTaskLifeCycle::new);
+ this.userTaskAssignmentStrategyConfig = singleton(userTaskAssignmentStrategyConfig, DefaultUserTaskAssignmentStrategyConfig::new);
+ this.userTaskInstances = singleton(userTaskInstances, InMemoryUserTaskInstances::new);
}
@@ -76,12 +86,16 @@ public DefaultUserTaskConfig(
UnitOfWorkManager unitOfWorkManager,
JobsService jobService,
IdentityProvider identityProvider,
- UserTaskLifeCycle userTaskLifeCycle) {
+ UserTaskLifeCycle userTaskLifeCycle,
+ DefaultUserTaskAssignmentStrategyConfig userTaskAssignmentStrategyConfig,
+ UserTaskInstances userTaskInstances) {
this.userTaskEventListeners = userTaskEventListenerConfig;
this.unitOfWorkManager = unitOfWorkManager;
this.jobService = jobService;
this.identityProvider = identityProvider;
this.userTaskLifeCycle = userTaskLifeCycle;
+ this.userTaskAssignmentStrategyConfig = userTaskAssignmentStrategyConfig;
+ this.userTaskInstances = userTaskInstances;
}
@Override
@@ -109,4 +123,14 @@ public UserTaskLifeCycle userTaskLifeCycle() {
return userTaskLifeCycle;
}
+ @Override
+ public UserTaskAssignmentStrategyConfig userTaskAssignmentStrategies() {
+ return userTaskAssignmentStrategyConfig;
+ }
+
+ @Override
+ public UserTaskInstances userTaskInstances() {
+ return userTaskInstances;
+ }
+
}
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskEventListenerConfig.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskEventListenerConfig.java
index 9cb7f3ac09e..086c729124f 100644
--- a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskEventListenerConfig.java
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTaskEventListenerConfig.java
@@ -32,8 +32,13 @@ public DefaultUserTaskEventListenerConfig() {
this.listeners = new ArrayList<>();
}
+ public DefaultUserTaskEventListenerConfig(Iterable listeners) {
+ this();
+ listeners.forEach(this::addUserTaskEventListener);
+ }
+
public DefaultUserTaskEventListenerConfig(List listeners) {
- this.listeners = new ArrayList<>(listeners);
+ this((Iterable) listeners);
}
public void addUserTaskEventListener(UserTaskEventListener userTaskEventListener) {
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 8adb9f07d02..e5265ae3f7f 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
@@ -19,7 +19,7 @@
package org.kie.kogito.usertask.impl;
import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -28,6 +28,7 @@
import java.util.Set;
import java.util.UUID;
+import org.kie.kogito.auth.IdentityProvider;
import org.kie.kogito.internal.usertask.event.KogitoUserTaskEventSupport;
import org.kie.kogito.internal.usertask.event.KogitoUserTaskEventSupport.AssignmentType;
import org.kie.kogito.usertask.UserTask;
@@ -35,7 +36,6 @@
import org.kie.kogito.usertask.UserTaskInstances;
import org.kie.kogito.usertask.lifecycle.UserTaskLifeCycle;
import org.kie.kogito.usertask.lifecycle.UserTaskState;
-import org.kie.kogito.usertask.lifecycle.UserTaskTransition;
import org.kie.kogito.usertask.lifecycle.UserTaskTransitionToken;
import org.kie.kogito.usertask.model.Attachment;
import org.kie.kogito.usertask.model.Comment;
@@ -46,6 +46,8 @@ public class DefaultUserTaskInstance implements UserTaskInstance {
private String id;
+ private String userTaskId;
+
private UserTaskState status;
private String actualOwner;
private String taskName;
@@ -75,6 +77,9 @@ public class DefaultUserTaskInstance implements UserTaskInstance {
private UserTaskLifeCycle setUserTaskLifeCycle;
public DefaultUserTaskInstance() {
+ this.inputs = new HashMap<>();
+ this.outputs = new HashMap<>();
+ this.status = UserTaskState.initalized();
this.metadata = new HashMap<>();
this.attachments = new ArrayList<>();
this.comments = new ArrayList<>();
@@ -86,27 +91,10 @@ public DefaultUserTaskInstance() {
}
public DefaultUserTaskInstance(UserTask userTask) {
+ this();
this.id = UUID.randomUUID().toString();
this.userTask = userTask;
this.instances = userTask.instances();
- this.status = UserTaskState.initalized();
- this.metadata = new HashMap<>();
- this.attachments = new ArrayList<>();
- this.comments = new ArrayList<>();
- this.potentialUsers = new HashSet<>();
- this.potentialGroups = new HashSet<>();
- this.adminUsers = new HashSet<>();
- this.adminGroups = new HashSet<>();
- this.excludedUsers = new HashSet<>();
- }
-
- public void assign() {
- Set potentialUsers = new HashSet<>(this.getPotentialUsers());
- potentialUsers.removeAll(getExcludedUsers());
-
- if (potentialUsers.size() == 1) {
- this.actualOwner = potentialUsers.iterator().next();
- }
}
public void setUserTaskEventSupport(KogitoUserTaskEventSupport userTaskEventSupport) {
@@ -121,22 +109,17 @@ public void setInstances(UserTaskInstances instances) {
this.instances = instances;
}
- @Override
- public void complete() {
- UserTaskTransitionToken transition = this.setUserTaskLifeCycle.newCompleteTransitionToken(this, Collections.emptyMap());
- transition(transition);
- instances.remove(id);
+ public void setId(String id) {
+ this.id = id;
}
@Override
- public void abort() {
- UserTaskTransitionToken transition = this.setUserTaskLifeCycle.newAbortTransitionToken(this, Collections.emptyMap());
- transition(transition);
- instances.remove(id);
+ public String getUserTaskId() {
+ return userTaskId;
}
- public void setId(String id) {
- this.id = id;
+ public void setUserTaskId(String userTaskId) {
+ this.userTaskId = userTaskId;
}
@Override
@@ -162,8 +145,9 @@ public boolean hasActualOwner() {
public void setActuaOwner(String actualOwner) {
this.actualOwner = actualOwner;
if (this.userTaskEventSupport != null) {
- this.userTaskEventSupport.fireOneUserTaskStateChange(this, this.status.getName(), this.status.getName());
+ this.userTaskEventSupport.fireOneUserTaskStateChange(this, this.status, this.status);
}
+ updatePersistence();
}
@Override
@@ -181,21 +165,29 @@ public void setExternalReferenceId(String externalReferenceId) {
}
@Override
- public UserTaskTransitionToken createTransitionToken(String transitionId, Map data) {
- return this.setUserTaskLifeCycle.newTransitionToken(transitionId, this, data);
- }
-
- @Override
- public void transition(UserTaskTransitionToken token) {
- Optional next = Optional.of(token);
+ public void transition(String transitionId, Map data, IdentityProvider identity) {
+ Optional next = Optional.of(this.setUserTaskLifeCycle.newTransitionToken(transitionId, this, data));
while (next.isPresent()) {
- UserTaskTransition transition = next.get().transition();
- next = this.setUserTaskLifeCycle.transition(this, token);
+ UserTaskTransitionToken transition = next.get();
+ next = this.setUserTaskLifeCycle.transition(this, transition, identity);
this.status = transition.target();
- this.userTaskEventSupport.fireOneUserTaskStateChange(this, transition.source().getName(), transition.target().getName());
- if (this.status.isTerminate().isPresent()) {
- this.instances.remove(this.id);
- }
+ this.updatePersistenceOrRemove();
+ this.userTaskEventSupport.fireOneUserTaskStateChange(this, transition.source(), transition.target());
+ }
+
+ }
+
+ private void updatePersistence() {
+ if (this.instances != null) {
+ this.instances.update(this);
+ }
+ }
+
+ private void updatePersistenceOrRemove() {
+ if (this.status.isTerminate()) {
+ this.instances.remove(this.id);
+ } else {
+ this.instances.update(this);
}
}
@@ -204,7 +196,7 @@ public UserTask getUserTask() {
return userTask;
}
- public void setUserTask(DefaultUserTask userTask) {
+ public void setUserTask(UserTask userTask) {
this.userTask = userTask;
}
@@ -213,7 +205,7 @@ public Map getInputs() {
}
public void setInputs(Map inputs) {
- this.inputs = inputs;
+ inputs.forEach(this::setInput);
}
public Map getOutputs() {
@@ -221,7 +213,25 @@ public Map getOutputs() {
}
public void setOutputs(Map outputs) {
- this.outputs = outputs;
+ outputs.forEach(this::setOutput);
+ }
+
+ @Override
+ public void setInput(String key, Object newValue) {
+ Object oldValue = this.inputs.put(key, newValue);
+ if (this.userTaskEventSupport != null) {
+ this.userTaskEventSupport.fireOnUserTaskInputVariableChange(this, key, oldValue, newValue);
+ }
+ updatePersistence();
+ }
+
+ @Override
+ public void setOutput(String key, Object newValue) {
+ Object oldValue = this.outputs.put(key, newValue);
+ if (this.userTaskEventSupport != null) {
+ this.userTaskEventSupport.fireOnUserTaskOutputVariableChange(this, key, oldValue, newValue);
+ }
+ updatePersistence();
}
/**
@@ -237,7 +247,14 @@ public String getTaskName() {
public void setTaskName(String taskName) {
this.taskName = taskName;
if (this.userTaskEventSupport != null) {
- this.userTaskEventSupport.fireOneUserTaskStateChange(this, this.status.getName(), this.status.getName());
+ this.userTaskEventSupport.fireOneUserTaskStateChange(this, this.status, this.status);
+ }
+ updatePersistence();
+ }
+
+ public void fireInitialStateChange() {
+ if (this.userTaskEventSupport != null) {
+ this.userTaskEventSupport.fireOneUserTaskStateChange(this, this.status, this.status);
}
}
@@ -254,8 +271,9 @@ public String getTaskDescription() {
public void setTaskDescription(String taskDescription) {
this.taskDescription = taskDescription;
if (this.userTaskEventSupport != null) {
- this.userTaskEventSupport.fireOneUserTaskStateChange(this, this.status.getName(), this.status.getName());
+ this.userTaskEventSupport.fireOneUserTaskStateChange(this, this.status, this.status);
}
+ updatePersistence();
}
/**
@@ -271,8 +289,9 @@ public Integer getTaskPriority() {
public void setTaskPriority(Integer taskPriority) {
this.taskPriority = taskPriority;
if (this.userTaskEventSupport != null) {
- this.userTaskEventSupport.fireOneUserTaskStateChange(this, this.status.getName(), this.status.getName());
+ this.userTaskEventSupport.fireOneUserTaskStateChange(this, this.status, this.status);
}
+ updatePersistence();
}
/**
@@ -291,6 +310,7 @@ public void setPotentialUsers(Set potentialUsers) {
if (this.userTaskEventSupport != null) {
this.userTaskEventSupport.fireOnUserTaskAssignmentChange(this, AssignmentType.USER_OWNERS, oldValues, potentialUsers);
}
+ updatePersistence();
}
/**
@@ -309,6 +329,7 @@ public void setPotentialGroups(Set potentialGroups) {
if (this.userTaskEventSupport != null) {
this.userTaskEventSupport.fireOnUserTaskAssignmentChange(this, AssignmentType.USER_GROUPS, oldValues, potentialGroups);
}
+ updatePersistence();
}
/**
@@ -327,6 +348,7 @@ public void setAdminUsers(Set adminUsers) {
if (this.userTaskEventSupport != null) {
this.userTaskEventSupport.fireOnUserTaskAssignmentChange(this, AssignmentType.ADMIN_USERS, oldValues, adminUsers);
}
+ updatePersistence();
}
/**
@@ -345,6 +367,7 @@ public void setAdminGroups(Set adminGroups) {
if (this.userTaskEventSupport != null) {
this.userTaskEventSupport.fireOnUserTaskAssignmentChange(this, AssignmentType.ADMIN_GROUPS, oldValues, adminGroups);
}
+ updatePersistence();
}
/**
@@ -363,6 +386,7 @@ public void setExcludedUsers(Set excludedUsers) {
if (this.userTaskEventSupport != null) {
this.userTaskEventSupport.fireOnUserTaskAssignmentChange(this, AssignmentType.USERS_EXCLUDED, oldValues, excludedUsers);
}
+ updatePersistence();
}
/**
@@ -370,41 +394,64 @@ public void setExcludedUsers(Set excludedUsers) {
*
* @return A map which key is the attachment id and value the attachment object
*/
+
public List getAttachments() {
return attachments;
}
@Override
- public void addAttachment(Attachment attachment) {
+ public Attachment addAttachment(Attachment attachment) {
+ attachment.setId(UUID.randomUUID().toString());
+ attachment.setUpdatedAt(new Date());
this.attachments.add(attachment);
if (this.userTaskEventSupport != null) {
this.userTaskEventSupport.fireOnUserTaskAttachmentAdded(this, attachment);
}
+ updatePersistence();
+ return attachment;
}
@Override
- public void updateAttachment(Attachment newAttachment) {
+ public Attachment updateAttachment(Attachment newAttachment) {
Optional oldAttachment = this.attachments.stream().filter(e -> e.getId().equals(newAttachment.getId())).findFirst();
if (oldAttachment.isEmpty()) {
- return;
+ return null;
}
this.attachments.remove(oldAttachment.get());
+ if (newAttachment.getName() == null) {
+ String path = newAttachment.getContent().getPath();
+ int idx = path.lastIndexOf("/");
+ if (idx > 0) {
+ path = path.substring(idx + 1);
+ }
+ newAttachment.setName(path);
+ }
+ newAttachment.setUpdatedAt(new Date());
this.attachments.add(newAttachment);
if (this.userTaskEventSupport != null) {
this.userTaskEventSupport.fireOnUserTaskAttachmentChange(this, oldAttachment.get(), newAttachment);
}
+ updatePersistence();
+ return newAttachment;
}
@Override
- public void removeAttachment(Attachment oldAttachment) {
- this.attachments.remove(oldAttachment);
+ public Attachment removeAttachment(Attachment attachment) {
+ Optional oldAttachment = this.attachments.stream().filter(e -> e.getId().equals(attachment.getId())).findFirst();
+ if (oldAttachment.isEmpty()) {
+ return null;
+ }
+ this.attachments.remove(attachment);
if (this.userTaskEventSupport != null) {
- this.userTaskEventSupport.fireOnUserTaskAttachmentDeleted(this, oldAttachment);
+ this.userTaskEventSupport.fireOnUserTaskAttachmentDeleted(this, oldAttachment.get());
}
+ updatePersistence();
+ return oldAttachment.get();
}
public void setAttachments(List attachments) {
this.attachments = attachments;
+ updatePersistence();
}
@@ -413,45 +460,61 @@ public void setAttachments(List attachments) {
*
* @return A map which key is the comment id and value the comment object
*/
+
public List getComments() {
return comments;
}
@Override
- public void addComment(Comment comment) {
+ public Comment addComment(Comment comment) {
+ comment.setId(UUID.randomUUID().toString());
+ comment.setUpdatedAt(new Date());
this.comments.add(comment);
if (this.userTaskEventSupport != null) {
this.userTaskEventSupport.fireOnUserTaskCommentAdded(this, comment);
}
+ updatePersistence();
+ return comment;
}
@Override
- public void updateComment(Comment newComment) {
+ public Comment updateComment(Comment newComment) {
Optional oldComment = this.comments.stream().filter(e -> e.getId().equals(newComment.getId())).findFirst();
if (oldComment.isEmpty()) {
- return;
+ return null;
}
this.comments.remove(oldComment.get());
+ newComment.setUpdatedAt(new Date());
this.comments.add(newComment);
if (this.userTaskEventSupport != null) {
this.userTaskEventSupport.fireOnUserTaskCommentChange(this, oldComment.get(), newComment);
}
+ updatePersistence();
+ return newComment;
}
@Override
- public void removeComment(Comment comment) {
+ public Comment removeComment(Comment comment) {
+ Optional oldComment = this.comments.stream().filter(e -> e.getId().equals(comment.getId())).findFirst();
+ if (oldComment.isEmpty()) {
+ return null;
+ }
this.comments.remove(comment);
if (this.userTaskEventSupport != null) {
- this.userTaskEventSupport.fireOnUserTaskCommentDeleted(this, comment);
+ this.userTaskEventSupport.fireOnUserTaskCommentDeleted(this, oldComment.get());
}
+ updatePersistence();
+ return oldComment.get();
}
public void setComments(List comments) {
this.comments = comments;
+ updatePersistence();
}
public void setMetadata(String key, Object value) {
this.metadata.put(key, value);
+ updatePersistence();
}
public Map getMetadata() {
@@ -460,6 +523,7 @@ public Map getMetadata() {
public void setMetadata(Map metadata) {
this.metadata = metadata;
+ updatePersistence();
}
@Override
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTasks.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTasks.java
index a2a664e82d8..e2918673324 100644
--- a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTasks.java
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/DefaultUserTasks.java
@@ -25,13 +25,18 @@
import java.util.Map;
import org.kie.kogito.Application;
+import org.kie.kogito.uow.events.UnitOfWorkUserTaskEventListener;
import org.kie.kogito.usertask.UserTask;
+import org.kie.kogito.usertask.UserTaskConfig;
+import org.kie.kogito.usertask.UserTaskInstance;
+import org.kie.kogito.usertask.UserTaskInstances;
import org.kie.kogito.usertask.UserTasks;
public class DefaultUserTasks implements UserTasks {
private Map userTasks;
private Application application;
+ private UserTaskInstances userTaskInstances;
public DefaultUserTasks() {
this.userTasks = new HashMap<>();
@@ -49,6 +54,9 @@ public DefaultUserTasks(Application application, Iterable userTasks) {
UserTask userTask = userTaskIterator.next();
this.userTasks.put(userTask.id(), userTask);
}
+ userTaskInstances = application.config().get(UserTaskConfig.class).userTaskInstances();
+ userTaskInstances.setDisconnectUserTaskInstance(this::disconnect);
+ userTaskInstances.setReconnectUserTaskInstance(this::connect);
}
@Override
@@ -61,4 +69,30 @@ public Collection userTaskIds() {
return userTasks.keySet();
}
+ @Override
+ public UserTaskInstances instances() {
+ return userTaskInstances;
+ }
+
+ public UserTaskInstance disconnect(UserTaskInstance userTaskInstance) {
+ DefaultUserTaskInstance instance = (DefaultUserTaskInstance) userTaskInstance;
+ instance.setUserTask(null);
+ instance.setUserTaskEventSupport(null);
+ instance.setUserTaskLifeCycle(null);
+ instance.setInstances(null);
+ return instance;
+ }
+
+ public UserTaskInstance connect(UserTaskInstance userTaskInstance) {
+ DefaultUserTaskInstance instance = (DefaultUserTaskInstance) userTaskInstance;
+ UserTaskConfig userTaskConfig = application.config().get(UserTaskConfig.class);
+ KogitoUserTaskEventSupportImpl impl = new KogitoUserTaskEventSupportImpl(userTaskConfig.identityProvider());
+ userTaskConfig.userTaskEventListeners().listeners().forEach(impl::addEventListener);
+ impl.addEventListener(new UnitOfWorkUserTaskEventListener(application.unitOfWorkManager()));
+ instance.setUserTask(application.get(UserTasks.class).userTaskById(instance.getUserTaskId()));
+ instance.setUserTaskEventSupport(impl);
+ instance.setUserTaskLifeCycle(userTaskConfig.userTaskLifeCycle());
+ instance.setInstances(userTaskInstances);
+ return instance;
+ }
}
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/InMemoryUserTaskInstances.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/InMemoryUserTaskInstances.java
index 6704fbd83a8..def2088da39 100644
--- a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/InMemoryUserTaskInstances.java
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/InMemoryUserTaskInstances.java
@@ -18,28 +18,42 @@
*/
package org.kie.kogito.usertask.impl;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Function;
+import org.kie.kogito.auth.IdentityProvider;
import org.kie.kogito.usertask.UserTaskInstance;
import org.kie.kogito.usertask.UserTaskInstances;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
public class InMemoryUserTaskInstances implements UserTaskInstances {
+ private static Logger LOG = LoggerFactory.getLogger(InMemoryUserTaskInstances.class);
+
private Map userTaskInstances;
private Function reconnectUserTaskInstance;
private Function disconnectUserTaskInstance;
private ObjectMapper mapper;
public InMemoryUserTaskInstances() {
+ LOG.info("Initializing InMemoryUsertaskInstances");
this.userTaskInstances = new HashMap<>();
- this.reconnectUserTaskInstance = Function.identity();
- this.disconnectUserTaskInstance = Function.identity();
+ this.reconnectUserTaskInstance = null;
+ this.disconnectUserTaskInstance = null;
this.mapper = new ObjectMapper();
+ this.mapper.registerModule(new JavaTimeModule());
}
@Override
@@ -55,13 +69,68 @@ public void setDisconnectUserTaskInstance(Function findById(String userTaskInstanceId) {
try {
+ if (!userTaskInstances.containsKey(userTaskInstanceId)) {
+ return Optional.empty();
+ }
UserTaskInstance userTaskInstance = mapper.readValue(userTaskInstances.get(userTaskInstanceId), DefaultUserTaskInstance.class);
return Optional.ofNullable(reconnectUserTaskInstance.apply(userTaskInstance));
} catch (Exception e) {
+ LOG.error("during find by Id {}", userTaskInstanceId, e);
return Optional.empty();
}
}
+ @Override
+ public List findByIdentity(IdentityProvider identity) {
+ try {
+ String user = identity.getName();
+ Collection roles = identity.getRoles();
+ List users = new ArrayList<>();
+ for (String id : userTaskInstances.keySet()) {
+ UserTaskInstance userTaskInstance = mapper.readValue(userTaskInstances.get(id), DefaultUserTaskInstance.class);
+ if (checkVisibility(userTaskInstance, user, roles)) {
+ users.add(reconnectUserTaskInstance.apply(userTaskInstance));
+ }
+ }
+ return users;
+ } catch (Exception e) {
+ LOG.error("during find by Identity {}", identity.getName(), e);
+ return Collections.emptyList();
+ }
+ }
+
+ private boolean checkVisibility(UserTaskInstance userTaskInstance, String user, Collection roles) {
+ Set adminUsers = userTaskInstance.getAdminUsers();
+ if (adminUsers.contains(user)) {
+ return true;
+ }
+
+ Set userAdminGroups = new HashSet<>(userTaskInstance.getAdminGroups());
+ userAdminGroups.retainAll(roles);
+ if (!userAdminGroups.isEmpty()) {
+ return true;
+ }
+
+ if (userTaskInstance.getActualOwner() != null && userTaskInstance.getActualOwner().equals(user)) {
+ return true;
+ }
+
+ // there is no user
+ Set users = new HashSet<>(userTaskInstance.getPotentialUsers());
+ users.removeAll(userTaskInstance.getExcludedUsers());
+ if (users.contains(user)) {
+ return true;
+ }
+
+ Set userPotGroups = new HashSet<>(userTaskInstance.getPotentialGroups());
+ userPotGroups.retainAll(roles);
+ if (!userPotGroups.isEmpty()) {
+ return true;
+ }
+
+ return false;
+ }
+
@Override
public boolean exists(String userTaskInstanceId) {
return userTaskInstances.containsKey(userTaskInstanceId);
@@ -74,6 +143,7 @@ public UserTaskInstance create(UserTaskInstance userTaskInstance) {
userTaskInstances.put(userTaskInstance.getId(), data);
return reconnectUserTaskInstance.apply(userTaskInstance);
} catch (Exception e) {
+ LOG.error("during create {}", userTaskInstance.getId(), e);
return null;
}
}
@@ -85,6 +155,7 @@ public UserTaskInstance update(UserTaskInstance userTaskInstance) {
userTaskInstances.put(userTaskInstance.getId(), data);
return userTaskInstance;
} catch (Exception e) {
+ LOG.error("during udpate {}", userTaskInstance.getId(), e);
return null;
}
}
@@ -92,8 +163,12 @@ public UserTaskInstance update(UserTaskInstance userTaskInstance) {
@Override
public UserTaskInstance remove(String userTaskInstanceId) {
try {
+ if (!userTaskInstances.containsKey(userTaskInstanceId)) {
+ return null;
+ }
return disconnectUserTaskInstance.apply(mapper.readValue(userTaskInstances.remove(userTaskInstanceId), DefaultUserTaskInstance.class));
} catch (Exception e) {
+ LOG.error("during remove {}", userTaskInstanceId, e);
return null;
}
}
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/KogitoUserTaskEventSupportImpl.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/KogitoUserTaskEventSupportImpl.java
index 1a2c3be5d6e..b337d159d4e 100644
--- a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/KogitoUserTaskEventSupportImpl.java
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/KogitoUserTaskEventSupportImpl.java
@@ -37,6 +37,7 @@
import org.kie.kogito.usertask.impl.events.UserTaskDeadlineEventImpl;
import org.kie.kogito.usertask.impl.events.UserTaskStateEventImpl;
import org.kie.kogito.usertask.impl.events.UserTaskVariableEventImpl;
+import org.kie.kogito.usertask.lifecycle.UserTaskState;
import org.kie.kogito.usertask.model.Attachment;
import org.kie.kogito.usertask.model.Comment;
@@ -84,7 +85,7 @@ private void fireUserTaskNotification(
@Override
public void fireOneUserTaskStateChange(
UserTaskInstance userTaskInstance,
- String oldStatus, String newStatus) {
+ UserTaskState oldStatus, UserTaskState newStatus) {
UserTaskStateEventImpl event = new UserTaskStateEventImpl(userTaskInstance, oldStatus, newStatus, identityProvider.getName());
event.setOldStatus(oldStatus);
event.setNewStatus(newStatus);
diff --git a/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/UserTaskServiceImpl.java b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/UserTaskServiceImpl.java
new file mode 100644
index 00000000000..da83176f6d8
--- /dev/null
+++ b/jbpm/jbpm-usertask/src/main/java/org/kie/kogito/usertask/impl/UserTaskServiceImpl.java
@@ -0,0 +1,265 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.kie.kogito.Application;
+import org.kie.kogito.auth.IdentityProvider;
+import org.kie.kogito.services.uow.UnitOfWorkExecutor;
+import org.kie.kogito.usertask.UserTaskConfig;
+import org.kie.kogito.usertask.UserTaskInstance;
+import org.kie.kogito.usertask.UserTaskService;
+import org.kie.kogito.usertask.UserTasks;
+import org.kie.kogito.usertask.lifecycle.UserTaskLifeCycle;
+import org.kie.kogito.usertask.lifecycle.UserTaskTransition;
+import org.kie.kogito.usertask.model.Attachment;
+import org.kie.kogito.usertask.model.Comment;
+import org.kie.kogito.usertask.view.UserTaskTransitionView;
+import org.kie.kogito.usertask.view.UserTaskView;
+
+public class UserTaskServiceImpl implements UserTaskService {
+
+ private Application application;
+
+ public UserTaskServiceImpl(Application application) {
+ this.application = application;
+ }
+
+ @Override
+ public Optional getUserTaskInstance(String taskId, IdentityProvider identity) {
+ return application.get(UserTasks.class).instances().findById(taskId).map(this::toUserTaskView);
+ }
+
+ @Override
+ public List list(IdentityProvider identity) {
+ return application.get(UserTasks.class).instances().findByIdentity(identity).stream().map(this::toUserTaskView).toList();
+ }
+
+ private UserTaskView toUserTaskView(UserTaskInstance instance) {
+ UserTaskView view = new UserTaskView();
+ view.setId(instance.getId());
+ view.setUserTaskId(instance.getUserTaskId());
+ view.setStatus(instance.getStatus());
+ view.setTaskName(instance.getTaskName());
+ view.setTaskDescription(instance.getTaskDescription());
+ view.setTaskPriority(instance.getTaskPriority());
+ view.setPotentialUsers(instance.getPotentialUsers());
+ view.setPotentialGroups(instance.getPotentialGroups());
+ view.setExcludedUsers(instance.getExcludedUsers());
+ view.setAdminUsers(instance.getAdminUsers());
+ view.setAdminGroups(instance.getAdminGroups());
+ view.setActualOwner(instance.getActualOwner());
+ view.setInputs(instance.getInputs());
+ view.setOutputs(instance.getOutputs());
+ view.setMetadata(instance.getMetadata());
+ return view;
+ }
+
+ @Override
+ public Optional transition(String taskId, String transitionId, Map data, IdentityProvider identity) {
+ return UnitOfWorkExecutor.executeInUnitOfWork(application.unitOfWorkManager(), () -> {
+ Optional userTaskInstance = application.get(UserTasks.class).instances().findById(taskId);
+ if (userTaskInstance.isEmpty()) {
+ return Optional.empty();
+ }
+ UserTaskInstance ut = userTaskInstance.get();
+ ut.transition(transitionId, data, identity);
+ return Optional.of(toUserTaskView(ut));
+ });
+ }
+
+ @Override
+ public List allowedTransitions(String taskId, IdentityProvider identity) {
+ Optional userTaskInstance = application.get(UserTasks.class).instances().findById(taskId);
+ if (userTaskInstance.isEmpty()) {
+ return Collections.emptyList();
+ }
+ UserTaskInstance ut = userTaskInstance.get();
+ UserTaskLifeCycle userTaskLifeCycle = application.config().get(UserTaskConfig.class).userTaskLifeCycle();
+ List transitions = userTaskLifeCycle.allowedTransitions(ut);
+ return toUserTaskTransitionView(transitions);
+ }
+
+ private List toUserTaskTransitionView(List transitions) {
+ List views = new ArrayList<>();
+ for (UserTaskTransition transition : transitions) {
+ UserTaskTransitionView view = new UserTaskTransitionView();
+ view.setTransitionId(transition.id());
+ view.setSource(transition.source());
+ view.setTarget(transition.target());
+ views.add(view);
+ }
+
+ return views;
+ }
+
+ @Override
+ public Optional