diff --git a/api/kogito-api/src/main/java/org/kie/kogito/process/WorkItem.java b/api/kogito-api/src/main/java/org/kie/kogito/process/WorkItem.java
index a936ffc762c..f3d11dcfcfd 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/process/WorkItem.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/process/WorkItem.java
@@ -21,6 +21,8 @@ public interface WorkItem {
String getId();
+ String getNodeId();
+
String getNodeInstanceId();
String getName();
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/process/workitem/TaskModel.java b/api/kogito-api/src/main/java/org/kie/kogito/process/workitem/TaskModel.java
new file mode 100644
index 00000000000..b730e0b59ac
--- /dev/null
+++ b/api/kogito-api/src/main/java/org/kie/kogito/process/workitem/TaskModel.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed 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.process.workitem;
+
+public interface TaskModel
{
+
+ String getId();
+
+ String getName();
+
+ int getState();
+
+ String getPhase();
+
+ String getPhaseStatus();
+
+ P getParameters();
+
+ R getResults();
+}
diff --git a/integration-tests/integration-tests-quarkus-processes/src/test/java/org/kie/kogito/integrationtests/quarkus/TaskTest.java b/integration-tests/integration-tests-quarkus-processes/src/test/java/org/kie/kogito/integrationtests/quarkus/TaskTest.java
index c5b0e220a1a..22ad1a2706a 100644
--- a/integration-tests/integration-tests-quarkus-processes/src/test/java/org/kie/kogito/integrationtests/quarkus/TaskTest.java
+++ b/integration-tests/integration-tests-quarkus-processes/src/test/java/org/kie/kogito/integrationtests/quarkus/TaskTest.java
@@ -106,6 +106,18 @@ void testSaveTask() {
.statusCode(200)
.extract()
.as(Map.class));
+
+ assertEquals(true, given().contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "admin")
+ .queryParam("group", "managers")
+ .pathParam("processId", processId)
+ .pathParam("taskId", taskId)
+ .get("/approvals/{processId}/firstLineApproval/{taskId}")
+ .then()
+ .statusCode(200)
+ .extract()
+ .path("results.approved"));
}
@Test
diff --git a/integration-tests/integration-tests-springboot/src/it/integration-tests-springboot-it/src/test/java/org/kie/kogito/integrationtests/springboot/TaskTest.java b/integration-tests/integration-tests-springboot/src/it/integration-tests-springboot-it/src/test/java/org/kie/kogito/integrationtests/springboot/TaskTest.java
index 238866b48c7..2cd986132be 100644
--- a/integration-tests/integration-tests-springboot/src/it/integration-tests-springboot-it/src/test/java/org/kie/kogito/integrationtests/springboot/TaskTest.java
+++ b/integration-tests/integration-tests-springboot/src/it/integration-tests-springboot-it/src/test/java/org/kie/kogito/integrationtests/springboot/TaskTest.java
@@ -259,6 +259,18 @@ void testSaveTask() {
.statusCode(200)
.extract()
.as(Map.class));
+
+ assertEquals(true , given().contentType(ContentType.JSON)
+ .when()
+ .queryParam("user", "admin")
+ .queryParam("group", "managers")
+ .pathParam("processId", processId)
+ .pathParam("taskId", taskId)
+ .get("/approvals/{processId}/firstLineApproval/{taskId}")
+ .then()
+ .statusCode(200)
+ .extract()
+ .path("results.approved"));
}
@Test
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/UserTaskModelMetaData.java
index 18b485b7453..9dbc4e72d68 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/UserTaskModelMetaData.java
@@ -34,10 +34,12 @@
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.comments.LineComment;
import com.github.javaparser.ast.expr.AssignExpr;
@@ -51,9 +53,13 @@
import com.github.javaparser.ast.expr.StringLiteralExpr;
import com.github.javaparser.ast.expr.ThisExpr;
import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import com.github.javaparser.ast.nodeTypes.NodeWithType;
+import com.github.javaparser.ast.nodeTypes.NodeWithVariables;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.ReturnStmt;
+import com.github.javaparser.ast.stmt.SwitchEntry;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
+import com.github.javaparser.ast.type.Type;
import static com.github.javaparser.StaticJavaParser.parse;
import static com.github.javaparser.StaticJavaParser.parseClassOrInterfaceType;
@@ -65,6 +71,7 @@ public class UserTaskModelMetaData {
private static final String TASK_INTPUT_CLASS_SUFFIX = "TaskInput";
private static final String TASK_OUTTPUT_CLASS_SUFFIX = "TaskOutput";
+ private static final String TASK_MODEL_CLASS_SUFFIX = "TaskModel";
private static final String TASK_NAME = "TaskName";
private static final String WORK_ITEM = "workItem";
private static final String PARAMS = "params";
@@ -84,6 +91,9 @@ public class UserTaskModelMetaData {
private String outputModelClassName;
private String outputModelClassSimpleName;
+ private String taskModelClassName;
+ private String taskModelClassSimpleName;
+
public UserTaskModelMetaData(String packageName, VariableScope processVariableScope, VariableScope variableScope, HumanTaskNode humanTaskNode, String processId) {
this.packageName = packageName;
this.processVariableScope = processVariableScope;
@@ -97,6 +107,9 @@ public UserTaskModelMetaData(String packageName, VariableScope processVariableSc
this.outputModelClassSimpleName = ucFirst(ProcessToExecModelGenerator.extractProcessId(processId) + "_" + humanTaskNode.getId() + "_" + TASK_OUTTPUT_CLASS_SUFFIX);
this.outputModelClassName = packageName + '.' + outputModelClassSimpleName;
+ this.taskModelClassSimpleName = ucFirst(ProcessToExecModelGenerator.extractProcessId(processId) + "_" + humanTaskNode.getId() + "_" + TASK_MODEL_CLASS_SUFFIX);
+ this.taskModelClassName = packageName + '.' + taskModelClassSimpleName;
+
}
public String generateInput() {
@@ -109,36 +122,21 @@ public String generateOutput() {
return modelClass.toString();
}
- public String getInputModelClassName() {
- return inputModelClassName;
- }
-
- public void setInputModelClassName(String inputModelClassName) {
- this.inputModelClassName = inputModelClassName;
- }
-
- public String getInputModelClassSimpleName() {
- return inputModelClassSimpleName;
+ public String generateModel() {
+ CompilationUnit modelClass = compilationUnitModel();
+ return modelClass.toString();
}
- public void setInputModelClassSimpleName(String inputModelClassSimpleName) {
- this.inputModelClassSimpleName = inputModelClassSimpleName;
+ public String getInputModelClassName() {
+ return inputModelClassName;
}
public String getOutputModelClassName() {
return outputModelClassName;
}
- public void setOutputModelClassName(String outputModelClassName) {
- this.outputModelClassName = outputModelClassName;
- }
-
- public String getOutputModelClassSimpleName() {
- return outputModelClassSimpleName;
- }
-
- public void setOutputModelClassSimpleName(String outputModelClassSimpleName) {
- this.outputModelClassSimpleName = outputModelClassSimpleName;
+ public String getTaskModelClassName() {
+ return taskModelClassName;
}
public String getName() {
@@ -187,21 +185,6 @@ private CompilationUnit compilationUnitInput() {
VariableDeclarationExpr itemField = new VariableDeclarationExpr(modelType, "item");
staticFromMap.addStatement(new AssignExpr(itemField, new ObjectCreationExpr(null, modelType, NodeList.nodeList()), AssignExpr.Operator.ASSIGN));
NameExpr item = new NameExpr("item");
- FieldAccessExpr idField = new FieldAccessExpr(item, "_id");
- staticFromMap.addStatement(new AssignExpr(idField, new MethodCallExpr(
- new NameExpr(WORK_ITEM), "getId"), AssignExpr.Operator.ASSIGN));
-
- FieldAccessExpr nameField = new FieldAccessExpr(item, "_name");
- staticFromMap.addStatement(new AssignExpr(nameField, new MethodCallExpr(
- new NameExpr(WORK_ITEM), "getName"), AssignExpr.Operator.ASSIGN));
-
- ClassOrInterfaceType toMap = new ClassOrInterfaceType(null, new SimpleName(Map.class.getSimpleName()),
- NodeList.nodeList(new ClassOrInterfaceType(null, String.class.getSimpleName()), new ClassOrInterfaceType(
- null,
- Object.class.getSimpleName())));
- VariableDeclarationExpr paramsField = new VariableDeclarationExpr(toMap, PARAMS);
- staticFromMap.addStatement(new AssignExpr(paramsField, new MethodCallExpr(
- new NameExpr(WORK_ITEM), "getParameters"), AssignExpr.Operator.ASSIGN));
for (Entry entry : humanTaskNode.getInMappings().entrySet()) {
@@ -268,7 +251,7 @@ private CompilationUnit compilationUnitInput() {
AssignExpr.Operator.ASSIGN));
}
Optional staticFromMethod = modelClass.findFirst(
- MethodDeclaration.class, sl -> sl.getName().asString().equals("from") && sl.isStatic());
+ MethodDeclaration.class, sl -> sl.getName().asString().equals("fromMap") && sl.isStatic());
if (staticFromMethod.isPresent()) {
MethodDeclaration from = staticFromMethod.get();
from.setType(modelClass.getNameAsString());
@@ -367,8 +350,60 @@ private CompilationUnit compilationUnitOutput() {
return compilationUnit;
}
+ private CompilationUnit compilationUnitModel() {
+ CompilationUnit compilationUnit = parse(this.getClass().getResourceAsStream(
+ "/class-templates/TaskModelTemplate.java"));
+ compilationUnit.setPackageDeclaration(packageName);
+ ClassOrInterfaceDeclaration modelClass = compilationUnit
+ .findFirst(ClassOrInterfaceDeclaration.class, sl1 -> true).orElseThrow(() -> new IllegalStateException(
+ "Cannot find class declaration in the template"));
+ compilationUnit.addOrphanComment(new LineComment("Task model for user task '" + humanTaskNode.getName() +
+ "' in process '" + processId + "'"));
+ modelClass.setName(taskModelClassSimpleName);
+ modelClass.getImplementedTypes().forEach(t -> t
+ .setTypeArguments(
+ NodeList.nodeList(parseClassOrInterfaceType(inputModelClassName), parseClassOrInterfaceType(
+ outputModelClassName))));
+ modelClass.findAll(NameExpr.class).forEach(this::templateReplacement);
+ modelClass.findAll(VariableDeclarationExpr.class).forEach(this::templateReplacement);
+ modelClass.findAll(FieldDeclaration.class).forEach(this::templateReplacement);
+ modelClass.findAll(ObjectCreationExpr.class).forEach(this::templateReplacement);
+ modelClass.findAll(MethodDeclaration.class).forEach(this::templateReplacement);
+ modelClass.findAll(Parameter.class).forEach(this::templateReplacement);
+ return compilationUnit;
+ }
+
+ private void templateReplacement(NameExpr name) {
+ name.setName(templateReplacement(name.getNameAsString()));
+ }
+
+ private void templateReplacement(NodeWithType expr) {
+ expr.setType(templateReplacement(expr.getTypeAsString()));
+ }
+
+ private void templateReplacement(NodeWithVariables expr) {
+ for (VariableDeclarator variable : expr.getVariables()) {
+ variable.setType(templateReplacement(variable.getTypeAsString()));
+ }
+ }
+
+ public String templateReplacement(String template) {
+ template = template.replace("$TaskInput$", inputModelClassName);
+ template = template.replace("$TaskOutput$", outputModelClassName);
+ template = template.replace("$TaskModel$", taskModelClassName);
+ return template;
+ }
+
public boolean isAdHoc() {
return !Boolean.parseBoolean((String) humanTaskNode.getMetaData(CUSTOM_AUTO_START))
&& (humanTaskNode.getIncomingConnections() == null || humanTaskNode.getIncomingConnections().isEmpty());
}
+
+ public SwitchEntry getModelSwitchEntry() {
+ SwitchEntry entry = new SwitchEntry();
+ entry.setLabels(NodeList.nodeList(new StringLiteralExpr(Long.toString(humanTaskNode.getId()))));
+ entry.addStatement(new ReturnStmt(new MethodCallExpr(new NameExpr(
+ taskModelClassSimpleName), new SimpleName("from")).addArgument(WORK_ITEM)));
+ return entry;
+ }
}
diff --git a/jbpm/jbpm-flow-builder/src/main/resources/class-templates/TaskInputTemplate.java b/jbpm/jbpm-flow-builder/src/main/resources/class-templates/TaskInputTemplate.java
index a0baf0b0d35..e071c46f2e5 100644
--- a/jbpm/jbpm-flow-builder/src/main/resources/class-templates/TaskInputTemplate.java
+++ b/jbpm/jbpm-flow-builder/src/main/resources/class-templates/TaskInputTemplate.java
@@ -20,26 +20,7 @@
public class XXXTaskInput {
- private String _id;
- private String _name;
-
- public void setId(String id) {
- this._id = id;
- }
-
- public String getId() {
- return this._id;
- }
-
- public void setName(String name) {
- this._name = name;
- }
-
- public String getName() {
- return this._name;
- }
-
- public static XXXTaskInput from(org.kie.kogito.process.WorkItem workItem) {
+ public static XXXTaskInput fromMap (Map params) {
}
}
\ No newline at end of file
diff --git a/jbpm/jbpm-flow-builder/src/main/resources/class-templates/TaskModelTemplate.java b/jbpm/jbpm-flow-builder/src/main/resources/class-templates/TaskModelTemplate.java
new file mode 100644
index 00000000000..2a526b2659c
--- /dev/null
+++ b/jbpm/jbpm-flow-builder/src/main/resources/class-templates/TaskModelTemplate.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed 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.jbpm.process.codegen;
+
+import org.kie.kogito.process.workitem.TaskModel;
+
+public class $TaskModel$ implements TaskModel<$TaskInput$, $TaskOutput$>{
+
+ private String id;
+ private String name;
+ private int state;
+ private String phase;
+ private String phaseStatus;
+ private $TaskInput$ parameters;
+ private $TaskOutput$ results;
+
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getState() {
+ return state;
+ }
+
+ public void setState (int state) {
+ this.state = state;
+ }
+
+ public String getPhase() {
+ return phase;
+ }
+
+ public void setPhase (String phase) {
+ this.phase = phase;
+ }
+
+ public String getPhaseStatus() {
+ return phaseStatus;
+ }
+
+ public void setPhaseStatus (String phaseStatus) {
+ this.phaseStatus = phaseStatus;
+ }
+
+ public $TaskInput$ getParameters () {
+ return parameters;
+ }
+
+ public void setParameters ($TaskInput$ parameters) {
+ this.parameters = parameters;
+ }
+
+ public $TaskOutput$ getResults () {
+ return results;
+ }
+
+ public void setParams ($TaskOutput$ results) {
+ this.results = results;
+ }
+
+ public static $TaskModel$ from(org.kie.kogito.process.WorkItem workItem) {
+ $TaskModel$ taskModel = new $TaskModel$();
+ taskModel.id= workItem.getId();
+ taskModel.name = workItem.getName();
+ taskModel.state = workItem.getState();
+ taskModel.phaseStatus = workItem.getPhaseStatus();
+ taskModel.phase = workItem.getPhase();
+ taskModel.parameters = $TaskInput$.fromMap(workItem.getParameters());
+ taskModel.results = $TaskOutput$.fromMap(workItem.getResults());
+ return taskModel;
+ }
+}
\ No newline at end of file
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 650839a9a51..205177092a0 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
@@ -403,6 +403,7 @@ public WorkItem workItem(String workItemId, Policy>... policies) {
.orElseThrow(() -> new WorkItemNotFoundException("Work item with id " + workItemId + " was not found in process instance " + id(), workItemId));
return new BaseWorkItem(workItemInstance.getStringId(),
workItemInstance.getWorkItem().getStringId(),
+ Long.toString(workItemInstance.getNode().getId()),
(String) workItemInstance.getWorkItem().getParameters().getOrDefault("TaskName", workItemInstance.getNodeName()),
workItemInstance.getWorkItem().getState(),
workItemInstance.getWorkItem().getPhaseId(),
@@ -418,6 +419,7 @@ public List workItems(Policy>... policies) {
.filter(ni -> ni instanceof WorkItemNodeInstance && ((WorkItemNodeInstance) ni).getWorkItem().enforce(policies))
.map(ni -> new BaseWorkItem(ni.getStringId(),
((WorkItemNodeInstance) ni).getWorkItemId(),
+ Long.toString(((WorkItemNodeInstance) ni).getNode().getId()),
(String) ((WorkItemNodeInstance) ni).getWorkItem().getParameters().getOrDefault("TaskName", ni.getNodeName()),
((WorkItemNodeInstance) ni).getWorkItem().getState(),
((WorkItemNodeInstance) ni).getWorkItem().getPhaseId(),
diff --git a/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/BaseWorkItem.java b/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/BaseWorkItem.java
index 8f4c7f2df81..b6ebce9147f 100644
--- a/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/BaseWorkItem.java
+++ b/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/BaseWorkItem.java
@@ -23,6 +23,7 @@ public class BaseWorkItem implements WorkItem {
private final String id;
private final String nodeInstanceId;
+ private final String nodeId;
private final String name;
private final int state;
@@ -32,9 +33,10 @@ public class BaseWorkItem implements WorkItem {
private Map parameters;
private Map results;
- public BaseWorkItem(String nodeInstanceId, String id, String name, int state, String phase, String phaseStatus, Map results) {
+ public BaseWorkItem(String nodeInstanceId, String id, String nodeId, String name, int state, String phase, String phaseStatus, Map results) {
this.id = id;
this.nodeInstanceId = nodeInstanceId;
+ this.nodeId = nodeId;
this.name = name;
this.state = state;
this.phase = phase;
@@ -42,9 +44,10 @@ public BaseWorkItem(String nodeInstanceId, String id, String name, int state, St
this.results = results;
}
- public BaseWorkItem(String nodeInstanceId, String id, String name, int state, String phase, String phaseStatus, Map parameters, Map results) {
+ public BaseWorkItem(String nodeInstanceId, String id, String nodeId, String name, int state, String phase, String phaseStatus, Map parameters, Map results) {
this.id = id;
this.nodeInstanceId = nodeInstanceId;
+ this.nodeId = nodeId;
this.name = name;
this.state = state;
this.phase = phase;
@@ -58,6 +61,11 @@ public String getId() {
return id;
}
+ @Override
+ public String getNodeId() {
+ return nodeId;
+ }
+
@Override
public String getName() {
return name;
diff --git a/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/process/ProcessCodegen.java b/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/process/ProcessCodegen.java
index 7f5908ce2ba..6b20c1ee07a 100644
--- a/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/process/ProcessCodegen.java
+++ b/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/process/ProcessCodegen.java
@@ -358,6 +358,8 @@ public Collection generate() {
storeFile(MODEL_TYPE, UserTasksModelClassGenerator.generatedFilePath(ut.getInputModelClassName()), ut.generateInput());
storeFile(MODEL_TYPE, UserTasksModelClassGenerator.generatedFilePath(ut.getOutputModelClassName()), ut.generateOutput());
+
+ storeFile(MODEL_TYPE, UserTasksModelClassGenerator.generatedFilePath(ut.getTaskModelClassName()), ut.generateModel());
}
}
@@ -365,6 +367,7 @@ public Collection generate() {
for (ProcessResourceGenerator resourceGenerator : rgs) {
storeFile(REST_TYPE, resourceGenerator.generatedFilePath(),
resourceGenerator.generate());
+ storeFile(MODEL_TYPE, UserTasksModelClassGenerator.generatedFilePath(resourceGenerator.getTaskModelFactoryClassName()), resourceGenerator.getTaskModelFactory());
}
}
diff --git a/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/process/ProcessResourceGenerator.java b/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/process/ProcessResourceGenerator.java
index b1a6623c543..bd1a7572ee3 100644
--- a/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/process/ProcessResourceGenerator.java
+++ b/kogito-codegen-modules/kogito-codegen-processes/src/main/java/org/kie/kogito/codegen/process/ProcessResourceGenerator.java
@@ -25,6 +25,7 @@
import java.util.stream.Collectors;
import org.drools.core.util.StringUtils;
+import org.jbpm.compiler.canonical.ProcessToExecModelGenerator;
import org.jbpm.compiler.canonical.UserTaskModelMetaData;
import org.kie.kogito.codegen.api.context.KogitoBuildContext;
import org.kie.kogito.codegen.api.context.impl.QuarkusKogitoBuildContext;
@@ -48,9 +49,12 @@
import com.github.javaparser.ast.expr.SimpleName;
import com.github.javaparser.ast.expr.StringLiteralExpr;
import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.stmt.SwitchStmt;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.Type;
+import static com.github.javaparser.StaticJavaParser.parse;
+import static org.drools.core.util.StringUtils.ucFirst;
import static org.kie.kogito.codegen.core.CodegenUtils.interpolateTypes;
/**
@@ -79,6 +83,8 @@ public class ProcessResourceGenerator {
private boolean dynamic;
private List userTasks;
private Map signals;
+ private CompilationUnit taskModelFactoryUnit;
+ private String taskModelFactoryClassName;
public ProcessResourceGenerator(
KogitoBuildContext context,
@@ -115,6 +121,14 @@ public ProcessResourceGenerator withTriggers(boolean startable, boolean dynamic)
return this;
}
+ public String getTaskModelFactory() {
+ return taskModelFactoryUnit.toString();
+ }
+
+ public String getTaskModelFactoryClassName() {
+ return taskModelFactoryClassName;
+ }
+
public String className() {
return resourceClazzName;
}
@@ -202,18 +216,31 @@ public String generate() {
// endpoints are not security annotated as they should restrict access based on user assignments
securityAnnotated(template);
- if (userTasks != null) {
+ Map typeInterpolations = new HashMap<>();
+ taskModelFactoryUnit = parse(this.getClass().getResourceAsStream("/class-templates/TaskModelFactoryTemplate.java"));
+ String taskModelFactorySimpleClassName = ucFirst(ProcessToExecModelGenerator.extractProcessId(processId) + "_" + "TaskModelFactory");
+ taskModelFactoryUnit.setPackageDeclaration(process.getPackageName());
+ taskModelFactoryClassName = process.getPackageName() + "." + taskModelFactorySimpleClassName;
+ ClassOrInterfaceDeclaration taskModelFactoryClass = taskModelFactoryUnit.findFirst(ClassOrInterfaceDeclaration.class).orElseThrow(IllegalStateException::new);
+ taskModelFactoryClass.setName(taskModelFactorySimpleClassName);
+ typeInterpolations.put("$TaskModelFactory$", taskModelFactoryClassName);
- CompilationUnit userTaskClazz = templateBuilder.build(context, REST_USER_TASK_TEMPLATE_NAME)
- .compilationUnitOrThrow();
+ if (userTasks != null && !userTasks.isEmpty()) {
+
+ CompilationUnit userTaskClazz = templateBuilder.build(context, REST_USER_TASK_TEMPLATE_NAME).compilationUnitOrThrow();
ClassOrInterfaceDeclaration userTaskTemplate = userTaskClazz
.findFirst(ClassOrInterfaceDeclaration.class)
.orElseThrow(() -> new NoSuchElementException("Compilation unit doesn't contain a class or interface declaration!"));
+
+ MethodDeclaration taskModelFactoryMethod = taskModelFactoryClass
+ .findFirst(MethodDeclaration.class, m -> m.getNameAsString().equals("from"))
+ .orElseThrow(IllegalStateException::new);
+ SwitchStmt switchExpr = taskModelFactoryMethod.getBody().map(b -> b.findFirst(SwitchStmt.class).orElseThrow(IllegalStateException::new)).orElseThrow(IllegalStateException::new);
+
for (UserTaskModelMetaData userTask : userTasks) {
String methodSuffix = sanitizeName(userTask.getName()) + "_" + index.getAndIncrement();
userTaskTemplate.findAll(MethodDeclaration.class).forEach(md -> {
-
MethodDeclaration cloned = md.clone();
template.addMethod(cloned.getName() + "_" + methodSuffix, Keyword.PUBLIC)
.setType(cloned.getType())
@@ -223,7 +250,7 @@ public String generate() {
});
template.findAll(StringLiteralExpr.class).forEach(s -> interpolateUserTaskStrings(s, userTask));
- template.findAll(ClassOrInterfaceType.class).forEach(c -> interpolateUserTaskTypes(c, userTask.getInputModelClassSimpleName(), userTask.getOutputModelClassSimpleName()));
+ template.findAll(ClassOrInterfaceType.class).forEach(c -> interpolateUserTaskTypes(c, userTask));
template.findAll(NameExpr.class).forEach(c -> interpolateUserTaskNameExp(c, userTask));
if (!userTask.isAdHoc()) {
template.findAll(MethodDeclaration.class)
@@ -231,13 +258,14 @@ public String generate() {
.filter(md -> md.getNameAsString().equals("signal_" + methodSuffix))
.collect(Collectors.toList()).forEach(template::remove);
}
+ switchExpr.getEntries().add(0, userTask.getModelSwitchEntry());
}
+
}
- template.findAll(StringLiteralExpr.class).forEach(this::interpolateStrings);
- Map typeInterpolations = new HashMap<>();
typeInterpolations.put("$Clazz$", resourceClazzName);
typeInterpolations.put("$Type$", dataClazzName);
+ template.findAll(StringLiteralExpr.class).forEach(this::interpolateStrings);
template.findAll(ClassOrInterfaceType.class).forEach(cls -> interpolateTypes(cls, typeInterpolations));
template.findAll(MethodDeclaration.class).forEach(this::interpolateMethods);
@@ -321,12 +349,7 @@ private void interpolateUserTaskStrings(StringLiteralExpr vv, UserTaskModelMetaD
}
private void interpolateUserTaskNameExp(NameExpr name, UserTaskModelMetaData userTask) {
- String identifier = name.getNameAsString();
-
- name.setName(identifier.replace("$TaskInput$", userTask.getInputModelClassSimpleName()));
-
- identifier = name.getNameAsString();
- name.setName(identifier.replace("$TaskOutput$", userTask.getOutputModelClassSimpleName()));
+ name.setName(userTask.templateReplacement(name.getNameAsString()));
}
private void interpolateMethods(MethodDeclaration m) {
@@ -336,30 +359,23 @@ private void interpolateMethods(MethodDeclaration m) {
m.setName(interpolated);
}
- private void interpolateUserTaskTypes(Type t, String inputClazzName, String outputClazzName) {
+ private void interpolateUserTaskTypes(Type t, UserTaskModelMetaData userTask) {
if (t.isArrayType()) {
t = t.asArrayType().getElementType();
}
if (t.isClassOrInterfaceType()) {
SimpleName returnType = t.asClassOrInterfaceType().getName();
- interpolateUserTaskTypes(returnType, inputClazzName, outputClazzName);
- t.asClassOrInterfaceType().getTypeArguments().ifPresent(o -> interpolateUserTaskTypeArguments(o,
- inputClazzName,
- outputClazzName));
+ interpolateUserTaskTypes(returnType, userTask);
+ t.asClassOrInterfaceType().getTypeArguments().ifPresent(o -> interpolateUserTaskTypeArguments(o, userTask));
}
}
- private void interpolateUserTaskTypes(SimpleName returnType, String inputClazzName, String outputClazzName) {
- String identifier = returnType.getIdentifier();
-
- returnType.setIdentifier(identifier.replace("$TaskInput$", inputClazzName));
-
- identifier = returnType.getIdentifier();
- returnType.setIdentifier(identifier.replace("$TaskOutput$", outputClazzName));
+ private void interpolateUserTaskTypes(SimpleName returnType, UserTaskModelMetaData userTask) {
+ returnType.setIdentifier(userTask.templateReplacement(returnType.getIdentifier()));
}
- private void interpolateUserTaskTypeArguments(NodeList ta, String inputClazzName, String outputClazzName) {
- ta.stream().forEach(t -> interpolateUserTaskTypes(t, inputClazzName, outputClazzName));
+ private void interpolateUserTaskTypeArguments(NodeList ta, UserTaskModelMetaData userTask) {
+ ta.stream().forEach(t -> interpolateUserTaskTypes(t, userTask));
}
private String sanitizeName(String name) {
diff --git a/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceQuarkusTemplate.java b/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceQuarkusTemplate.java
index 3e1494aa587..82adff1666c 100644
--- a/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceQuarkusTemplate.java
+++ b/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceQuarkusTemplate.java
@@ -54,6 +54,7 @@
import org.kie.kogito.process.workitem.AttachmentInfo;
import org.kie.kogito.process.workitem.Comment;
import org.kie.kogito.process.workitem.Policies;
+import org.kie.kogito.process.workitem.TaskModel;
import org.kie.kogito.process.impl.Sig;
import org.kie.kogito.services.uow.UnitOfWorkExecutor;
import org.kie.kogito.auth.IdentityProvider;
@@ -106,7 +107,7 @@ public class $Type$Resource {
return process.instances()
.findById(id, ProcessInstanceReadMode.READ_ONLY)
.map(pi -> pi.variables().toOutput())
- .orElseThrow(() -> new NotFoundException());
+ .orElseThrow(NotFoundException::new);
}
@DELETE
@@ -122,7 +123,7 @@ public class $Type$Resource {
pi.abort();
return pi.checkError().variables().toOutput();
}))
- .orElseThrow(() -> new NotFoundException());
+ .orElseThrow(NotFoundException::new);
}
@PUT
@@ -136,19 +137,23 @@ public class $Type$Resource {
.instances()
.findById(id)
.map(pi -> pi.updateVariables(resource).toOutput()))
- .orElseThrow(() -> new NotFoundException());
+ .orElseThrow(NotFoundException::new);
}
@GET
@Path("/{id}/tasks")
@Produces(MediaType.APPLICATION_JSON)
- public List getTasks_$name$(@PathParam("id") String id,
+ public List getTasks_$name$(@PathParam("id") String id,
@QueryParam("user") final String user,
@QueryParam("group") final List groups) {
return process.instances()
.findById(id, ProcessInstanceReadMode.READ_ONLY)
- .map(pi -> pi.workItems(Policies.of(user, groups)))
- .orElseThrow(() -> new NotFoundException());
+ .map(pi -> pi
+ .workItems(Policies.of(user, groups))
+ .stream()
+ .map($TaskModelFactory$::from)
+ .collect(Collectors.toList()))
+ .orElseThrow(NotFoundException::new);
}
}
diff --git a/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceSpringTemplate.java b/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceSpringTemplate.java
index 7b95e78147a..cef2c6abf06 100644
--- a/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceSpringTemplate.java
+++ b/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceSpringTemplate.java
@@ -35,6 +35,7 @@
import org.kie.kogito.process.workitem.AttachmentInfo;
import org.kie.kogito.process.workitem.Comment;
import org.kie.kogito.process.workitem.Policies;
+import org.kie.kogito.process.workitem.TaskModel;
import org.kie.kogito.services.uow.UnitOfWorkExecutor;
import org.jbpm.process.instance.impl.humantask.HumanTaskHelper;
import org.jbpm.process.instance.impl.humantask.HumanTaskTransition;
@@ -134,13 +135,18 @@ public class $Type$Resource {
}
@GetMapping(value = "/{id}/tasks", produces = MediaType.APPLICATION_JSON_VALUE)
- public ResponseEntity> getTasks_$name$(@PathVariable("id") String id,
+ public ResponseEntity> getTasks_$name$(@PathVariable("id") String id,
@RequestParam(value = "user", required = false) final String user,
@RequestParam(value = "group", required = false) final List groups) {
return process.instances()
.findById(id, ProcessInstanceReadMode.READ_ONLY)
- .map(pi -> pi.workItems(Policies.of(user, groups)))
+ .map(pi -> pi
+ .workItems(Policies.of(user, groups))
+ .stream()
+ .map($TaskModelFactory$::from)
+ .collect(Collectors.toList()))
.map(m -> ResponseEntity.ok(m))
.orElseGet(() -> ResponseEntity.notFound().build());
+
}
}
diff --git a/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceUserTaskQuarkusTemplate.java b/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceUserTaskQuarkusTemplate.java
index 0eca453ec7d..705c3e2213e 100644
--- a/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceUserTaskQuarkusTemplate.java
+++ b/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceUserTaskQuarkusTemplate.java
@@ -55,7 +55,7 @@ public Response signal(@PathParam("id") final String id, @Context UriInfo uriInf
}
return Response.status(Response.Status.NOT_FOUND).build();
});
- }).orElseThrow(() -> new NotFoundException());
+ }).orElseThrow(NotFoundException::new);
}
@POST
@@ -81,7 +81,7 @@ public Response signal(@PathParam("id") final String id, @Context UriInfo uriInf
HumanTaskTransition.withModel(phase, model, Policies.of(user, groups)));
return pi.variables().toOutput();
}))
- .orElseThrow(() -> new NotFoundException());
+ .orElseThrow(NotFoundException::new);
}
@@ -103,7 +103,7 @@ public Response signal(@PathParam("id") final String id, @Context UriInfo uriInf
taskId,
wi -> HumanTaskHelper.updateContent(wi, model),
Policies.of(user,groups)))))
- .orElseThrow(() -> new NotFoundException());
+ .orElseThrow(NotFoundException::new);
}
@@ -130,7 +130,7 @@ public Response signal(@PathParam("id") final String id, @Context UriInfo uriInf
HumanTaskTransition.withModel(phase, model, Policies.of(user, groups)));
return pi.variables().toOutput();
}))
- .orElseThrow(() -> new NotFoundException());
+ .orElseThrow(NotFoundException::new);
}
@@ -138,14 +138,14 @@ public Response signal(@PathParam("id") final String id, @Context UriInfo uriInf
@GET
@Path("/{id}/$taskName$/{taskId}")
@Produces(MediaType.APPLICATION_JSON)
- public $TaskInput$ getTask(@PathParam("id") String id,
+ public $TaskModel$ getTask(@PathParam("id") String id,
@PathParam("taskId") String taskId,
@QueryParam("user") final String user,
@QueryParam("group") final List groups) {
return process.instances()
.findById(id, ProcessInstanceReadMode.READ_ONLY)
- .map(pi -> $TaskInput$.from(pi.workItem(taskId, Policies.of(user, groups))))
- .orElseThrow(() -> new NotFoundException());
+ .map(pi -> $TaskModel$.from(pi.workItem(taskId, Policies.of(user, groups))))
+ .orElseThrow(NotFoundException::new);
}
@GET
@@ -190,7 +190,7 @@ public Map getSchemaAndPhases(@PathParam("id") final String id,
Policies.of(user, groups)));
return pi.variables().toOutput();
}))
- .orElseThrow(() -> new NotFoundException());
+ .orElseThrow(NotFoundException::new);
}
@POST
@@ -218,7 +218,7 @@ public Response addComment(@PathParam("id") final String id,
.toString())
.build()).entity(comment).build();
})
- .orElseThrow(() -> new NotFoundException()));
+ .orElseThrow(NotFoundException::new));
}
@PUT
@@ -241,7 +241,7 @@ public Comment updateComment(@PathParam("id") final String id,
taskId,
wi -> HumanTaskHelper.updateComment(wi, commentId, comment, user),
Policies.of(user, groups)))
- .orElseThrow(() -> new NotFoundException()));
+ .orElseThrow(NotFoundException::new));
}
@DELETE
@@ -264,7 +264,7 @@ public Response deleteComment(@PathParam("id") final String id,
Policies.of(user, groups));
return (removed ? Response.ok() : Response.status(Status.NOT_FOUND)).build();
})
- .orElseThrow(() -> new NotFoundException()));
+ .orElseThrow(NotFoundException::new));
}
@POST
@@ -292,7 +292,7 @@ public Response addAttachment(@PathParam("id") final String id,
.toString())
.build()).entity(attachment).build();
})
- .orElseThrow(() -> new NotFoundException()));
+ .orElseThrow(NotFoundException::new));
}
@PUT
@@ -315,7 +315,7 @@ public Attachment updateAttachment(@PathParam("id") final String id,
taskId,
wi -> HumanTaskHelper.updateAttachment(wi, attachmentId, attachment, user),
Policies.of(user, groups)))
- .orElseThrow(() -> new NotFoundException()));
+ .orElseThrow(NotFoundException::new));
}
@DELETE
@@ -338,7 +338,7 @@ public Response deleteAttachment(@PathParam("id") final String id,
Policies.of(user, groups));
return (removed ? Response.ok() : Response.status(Status.NOT_FOUND)).build();
})
- .orElseThrow(() -> new NotFoundException()));
+ .orElseThrow(NotFoundException::new));
}
@GET
@@ -350,7 +350,7 @@ public Attachment getAttachment(@PathParam("id") final String id,
@QueryParam("user") final String user,
@QueryParam("group") final List groups) {
Attachment attachment = HumanTaskHelper.findTask(process.instances().findById(id).orElseThrow(
- () -> new NotFoundException()), taskId, Policies.of(user, groups))
+ NotFoundException::new), taskId, Policies.of(user, groups))
.getAttachments().get(attachmentId);
if (attachment == null) {
throw new NotFoundException("Attachment " + attachmentId + " not found");
@@ -365,7 +365,7 @@ public Collection getAttachments(@PathParam("id") final String id,
@PathParam("taskId") final String taskId,
@QueryParam("user") final String user,
@QueryParam("group") final List groups) {
- return HumanTaskHelper.findTask(process.instances().findById(id).orElseThrow(() -> new NotFoundException()),
+ return HumanTaskHelper.findTask(process.instances().findById(id).orElseThrow(NotFoundException::new),
taskId, Policies.of(user, groups))
.getAttachments().values();
}
@@ -379,7 +379,7 @@ public Comment getComment(@PathParam("id") final String id,
@QueryParam("user") final String user,
@QueryParam("group") final List groups) {
Comment comment = HumanTaskHelper.findTask(process.instances().findById(id).orElseThrow(
- () -> new NotFoundException()), taskId, Policies.of(user, groups))
+ NotFoundException::new), taskId, Policies.of(user, groups))
.getComments().get(commentId);
if (comment == null) {
throw new NotFoundException("Comment " + commentId + " not found");
@@ -394,7 +394,7 @@ public Collection getComments(@PathParam("id") final String id,
@PathParam("taskId") final String taskId,
@QueryParam("user") final String user,
@QueryParam("group") final List groups) {
- return HumanTaskHelper.findTask(process.instances().findById(id).orElseThrow(() -> new NotFoundException()),
+ return HumanTaskHelper.findTask(process.instances().findById(id).orElseThrow(NotFoundException::new),
taskId, Policies.of(user, groups))
.getComments().values();
}
diff --git a/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceUserTaskSpringTemplate.java b/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceUserTaskSpringTemplate.java
index 2d89bd1e178..f47d27a403c 100644
--- a/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceUserTaskSpringTemplate.java
+++ b/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/RestResourceUserTaskSpringTemplate.java
@@ -345,7 +345,7 @@ public ResponseEntity> getComments(@PathVariable("id") final
}
@GetMapping(value = "/{id}/$taskName$/{taskId}", produces = MediaType.APPLICATION_JSON_VALUE)
- public ResponseEntity<$TaskInput$> getTask(@PathVariable("id") String id,
+ public ResponseEntity<$TaskModel$> getTask(@PathVariable("id") String id,
@PathVariable("taskId") String taskId,
@RequestParam(value = "user", required = false) final String user,
@RequestParam(value = "group",
@@ -353,7 +353,7 @@ public ResponseEntity> getComments(@PathVariable("id") final
return process
.instances()
.findById(id)
- .map(pi -> $TaskInput$.from(pi.workItem(taskId, Policies.of(user, groups))))
+ .map(pi -> $TaskModel$.from(pi.workItem(taskId, Policies.of(user, groups))))
.map(m -> ResponseEntity.ok(m))
.orElseGet(() -> ResponseEntity.notFound().build());
}
diff --git a/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/TaskModelFactoryTemplate.java b/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/TaskModelFactoryTemplate.java
new file mode 100644
index 00000000000..03d52c78707
--- /dev/null
+++ b/kogito-codegen-modules/kogito-codegen-processes/src/main/resources/class-templates/TaskModelFactoryTemplate.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed 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.jbpm.process.codegen;
+
+import org.kie.kogito.process.workitem.TaskModel;
+
+public class $TaskModelFactory$ {
+
+ public static TaskModel from(org.kie.kogito.process.WorkItem workItem) {
+ switch (workItem.getNodeId()) {
+ default:
+ throw new IllegalArgumentException("Invalid task name for work item "+workItem);
+ }
+ }
+}
\ No newline at end of file