Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[KOGITO-4502] GET task id API to return task info, not only the input model #1217

Merged
merged 1 commit into from
Apr 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ public interface WorkItem {

String getId();

default String getNodeId() {
throw new UnsupportedOperationException();
}

String getNodeInstanceId();

String getName();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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;

/**
* Process view of a work item.<br>
* It includes only parameters and results as defined in process plus getters to get the active phase.<br>
*
* @param <P> Input generated class
* @param <R> Output generated class
*/
public interface TaskModel<P, R> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the name TaskModel, in this case, it is representing a Task from the REST endpoint perspective... the "model" seems that this is the input/output of a task... just want to avoid confusion of what is this different from other input/output model classes.
@evacchi wdyt, ideas? because Model concept in the new API is more like the context of a unit (that in this case would be a task)...

Copy link
Contributor Author

@fjtirado fjtirado Apr 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The task model is the composition of the input and the output, I think this is the proper name (I though of it while writing the blog), but if anyone can think of a better one, we can change it for sure


String getId();

String getName();

int getState();

String getPhase();

String getPhaseStatus();

P getParameters();

R getResults();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.kie.kogito.integrationtests.springboot;

import java.util.Collections;

import java.util.HashMap;
import java.util.Map;

Expand All @@ -26,7 +27,7 @@
import org.acme.examples.model.Rating;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kie.kogito.process.WorkItem;
import org.kie.kogito.process.workitem.TaskModel;
import org.kie.kogito.testcontainers.springboot.InfinispanSpringBootTestResource;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
Expand Down Expand Up @@ -66,7 +67,7 @@ void testSubmitMovie() {
.extract()
.path("id");

WorkItem task = given()
TaskModel task = given()
.when()
.get("/cinema/{pid}/tasks", pid)
.then()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
package org.kie.kogito.integrationtests.springboot;

import java.util.Map;
import org.kie.kogito.process.workitem.TaskModel;

import org.kie.kogito.process.WorkItem;


public class TestWorkItem implements WorkItem {
public class TestWorkItem implements TaskModel<Map<String,Object>,Map<String,Object>> {
/*
* It is interesting to have an implementation of WorkItem for testing that
* the information returned by REST API is consistent with the interface definition.
Expand All @@ -30,7 +29,6 @@ public class TestWorkItem implements WorkItem {
*/

private String id;
private String nodeInstanceId;
private String name;
private int state;
private String phase;
Expand All @@ -46,14 +44,6 @@ public void setId(String id) {
this.id = id;
}

public String getNodeInstanceId() {
return nodeInstanceId;
}

public void setNodeInstanceId(String nodeInstanceId) {
this.nodeInstanceId = nodeInstanceId;
}

public String getName() {
return name;
}
Expand Down Expand Up @@ -101,6 +91,4 @@ public Map<String, Object> getResults() {
public void setResults(Map<String, Object> results) {
this.results = results;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,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;
Expand All @@ -52,9 +54,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;
Expand All @@ -66,6 +72,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";
Expand All @@ -85,6 +92,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;
Expand All @@ -98,6 +108,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() {
Expand All @@ -110,36 +123,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() {
Expand All @@ -166,18 +164,17 @@ private void addUserTaskParamAnnotation(FieldDeclaration fd, UserTaskParam.Param
fd.addAndGetAnnotation(UserTaskParam.class).addPair("value", ParamType.class.getSimpleName() + '.' + paramType);
}

private RuntimeException cannotFindClass() {
return new IllegalStateException("Cannot find class declaration in the template");
}

private CompilationUnit compilationUnitInput() {
// task input handling
CompilationUnit compilationUnit = parse(this.getClass().getResourceAsStream("/class-templates/TaskInputTemplate.java"));
compilationUnit.setPackageDeclaration(packageName);
Optional<ClassOrInterfaceDeclaration> processMethod = compilationUnit.findFirst(ClassOrInterfaceDeclaration.class, sl1 -> true);

if (!processMethod.isPresent()) {
throw new RuntimeException("Cannot find class declaration in the template");
}
ClassOrInterfaceDeclaration modelClass = processMethod.get();
compilationUnit.addOrphanComment(new LineComment("Task input model for user task '" + humanTaskNode.getName() + "' in process '" + processId + "'"));

ClassOrInterfaceDeclaration modelClass = compilationUnit.findFirst(ClassOrInterfaceDeclaration.class,
sl1 -> true).orElseThrow(this::cannotFindClass);
addComment(compilationUnit, "Task input");
addUserTaskAnnotation(modelClass);

modelClass.setName(inputModelClassSimpleName);
Expand All @@ -188,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<String, String> entry : humanTaskNode.getInMappings().entrySet()) {

Expand Down Expand Up @@ -271,7 +253,7 @@ private CompilationUnit compilationUnitInput() {
AssignExpr.Operator.ASSIGN));
}
Optional<MethodDeclaration> 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());
Expand All @@ -285,11 +267,8 @@ private CompilationUnit compilationUnitInput() {
private CompilationUnit compilationUnitOutput() {
CompilationUnit compilationUnit = parse(this.getClass().getResourceAsStream("/class-templates/TaskOutputTemplate.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 output model for user task '" + humanTaskNode.getName() + "' in process '" + processId + "'"));
ClassOrInterfaceDeclaration modelClass = compilationUnit.findFirst(ClassOrInterfaceDeclaration.class, sl1 -> true).orElseThrow(this::cannotFindClass);
addComment(compilationUnit, "Task output");
addUserTaskAnnotation(modelClass);
modelClass.setName(outputModelClassSimpleName);

Expand Down Expand Up @@ -370,8 +349,62 @@ 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(this::cannotFindClass);
addComment(compilationUnit, "Task model");
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 addComment(CompilationUnit unit, String prefix) {
unit.addOrphanComment(new LineComment(prefix + " for user task '" + humanTaskNode.getName() + "' in process '" + processId + "'"));
}

private void templateReplacement(NameExpr name) {
name.setName(templateReplacement(name.getNameAsString()));
}

private <T extends Node, R extends Type> void templateReplacement(NodeWithType<T, R> expr) {
expr.setType(templateReplacement(expr.getTypeAsString()));
}

private <T extends Node> void templateReplacement(NodeWithVariables<T> 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;
}
}
Loading