提交 0badd2a8 编写于 作者: F Frederik Heremans

Added taskVariableXXX methods to rest for types JSON supports + test

上级 b19f6668
......@@ -17,6 +17,7 @@ import org.activiti.engine.ActivitiException;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.ActivitiObjectNotFoundException;
import org.activiti.engine.ActivitiOptimisticLockingException;
import org.codehaus.jackson.map.JsonMappingException;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.Status;
......@@ -35,6 +36,21 @@ public class ActivitiStatusService extends StatusService {
@Override
public Status getStatus(Throwable throwable, Request request, Response response) {
Status status = null;
if(throwable instanceof JsonMappingException && throwable.getCause() != null) {
// Possible that the Jackson-unmarchalling has a more specific cause. if no specific exception caused
// the throwable, it will be handled as a normal exception
status = getSpecificStatus(throwable.getCause(), request, response);
}
if(status == null) {
status = getSpecificStatus(throwable, request, response);
}
return status != null ? status : Status.SERVER_ERROR_INTERNAL;
}
protected Status getSpecificStatus(Throwable throwable, Request request, Response response) {
Status status = null;
if(throwable instanceof ActivitiObjectNotFoundException) {
// 404 - Entity not found
status = new Status(Status.CLIENT_ERROR_NOT_FOUND.getCode(), throwable.getMessage(), null, null);
......@@ -48,8 +64,9 @@ public class ActivitiStatusService extends StatusService {
ResourceException re = (ResourceException) throwable;
status = re.getStatus();
} else {
status = new Status(Status.SERVER_ERROR_INTERNAL.getCode(), throwable.getMessage(), null, null);
status = null;
}
return status;
}
}
/* 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.activiti.rest.api.task;
import org.activiti.engine.ActivitiIllegalArgumentException;
/**
* @author Frederik Heremans
*/
public class QueryVariable {
private String name;
private String operation;
private Object value;
private String type;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public QueryVariableOperation getVariableOperation() {
if(operation == null) {
return null;
}
return QueryVariableOperation.forFriendlyName(operation);
}
public void setOperation(String operation) {
this.operation = operation;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public enum QueryVariableOperation {
EQUALS("equals"),
NOT_EQUALS("notEquals"),
EQUALS_IGNORE_CASE("equalsIgnoreCase"),
NOT_EQUALS_IGNORE_CASE("notEqualsIgnoreCase"),
LIKE("like"),
GREATER_THAN("greaterThan"),
GREATER_THAN_OR_EQUALS("greaterThanOrEquals"),
LESS_THAN("lessThan"),
LESS_THAN_OR_EQUALS("lessThanOrEquals");
private String friendlyName;
private QueryVariableOperation(String friendlyName) {
this.friendlyName = friendlyName;
}
public String getFriendlyName() {
return friendlyName;
}
public static QueryVariableOperation forFriendlyName(String friendlyName) {
for(QueryVariableOperation type : values()) {
if(type.friendlyName.equals(friendlyName)) {
return type;
}
}
throw new ActivitiIllegalArgumentException("Unsupported variable query operation: " + friendlyName);
}
}
}
......@@ -14,6 +14,7 @@
package org.activiti.rest.api.task;
import java.util.HashMap;
import java.util.List;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.impl.TaskQueryProperty;
......@@ -24,6 +25,7 @@ import org.activiti.engine.task.TaskQuery;
import org.activiti.rest.api.ActivitiUtil;
import org.activiti.rest.api.DataResponse;
import org.activiti.rest.api.SecuredResource;
import org.activiti.rest.api.task.QueryVariable.QueryVariableOperation;
import org.restlet.data.Form;
......@@ -181,6 +183,68 @@ public class TaskBasedResource extends SecuredResource {
}
}
if(request.getTaskVariables() != null) {
processTaskvariables(taskQuery, request.getTaskVariables());
}
return new TaskPaginateList(this).paginateList(query, taskQuery, "id", properties);
}
protected void processTaskvariables(TaskQuery taskQuery, List<QueryVariable> variables) {
for(QueryVariable variable : variables) {
if(variable.getVariableOperation() == null) {
throw new ActivitiIllegalArgumentException("Variable operation is missing for variable: " + variable.getName());
}
if(variable.getValue() == null) {
throw new ActivitiIllegalArgumentException("Variable value is missing for variable: " + variable.getName());
}
boolean nameLess = variable.getName() == null;
Object actualValue = variable.getValue();
if(variable.getType() != null) {
// Perform explicit conversion instead of using raw value from request
// TODO: use pluggable variable-creator based on objects and type
}
// A value-only query is only possible using equals-operator
if(nameLess && variable.getVariableOperation() != QueryVariableOperation.EQUALS) {
throw new ActivitiIllegalArgumentException("Value-only query (without a variable-name) is only supported when using 'equals' operation.");
}
switch(variable.getVariableOperation()) {
case EQUALS:
if(nameLess) {
taskQuery.taskVariableValueEquals(actualValue);
} else {
taskQuery.taskVariableValueEquals(variable.getName(), actualValue);
}
break;
case EQUALS_IGNORE_CASE:
if(actualValue instanceof String) {
taskQuery.taskVariableValueEqualsIgnoreCase(variable.getName(), (String)actualValue);
} else {
throw new ActivitiIllegalArgumentException("Only string variable values are supported when ignoring casing, but was: " + actualValue.getClass().getName());
}
break;
case NOT_EQUALS:
taskQuery.taskVariableValueNotEquals(variable.getName(), actualValue);
break;
case NOT_EQUALS_IGNORE_CASE:
if(actualValue instanceof String) {
taskQuery.taskVariableValueNotEqualsIgnoreCase(variable.getName(), (String)actualValue);
} else {
throw new ActivitiIllegalArgumentException("Only string variable values are supported when ignoring casing, but was: " + actualValue.getClass().getName());
}
break;
default:
throw new ActivitiIllegalArgumentException("Unsupported variable query operation: " + variable.getVariableOperation());
}
}
}
}
......@@ -14,6 +14,10 @@
package org.activiti.rest.api.task;
import java.util.Date;
import java.util.List;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.annotate.JsonTypeInfo.Id;
/**
......@@ -49,6 +53,8 @@ public class TaskQueryRequest {
private Date dueAfter;
private Boolean active;
private List<QueryVariable> taskVariables;
public String getName() {
return name;
}
......@@ -264,4 +270,13 @@ public class TaskQueryRequest {
public void setActive(Boolean active) {
this.active = active;
}
@JsonTypeInfo(use=Id.CLASS, defaultImpl=QueryVariable.class)
public List<QueryVariable> getTaskVariables() {
return taskVariables;
}
public void setTaskVariables(List<QueryVariable> taskVariables) {
this.taskVariables = taskVariables;
}
}
......@@ -14,6 +14,7 @@
package org.activiti.rest.api.runtime;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import org.activiti.engine.impl.util.ClockUtil;
......@@ -24,7 +25,10 @@ import org.activiti.engine.task.Task;
import org.activiti.engine.test.Deployment;
import org.activiti.rest.BaseRestTestCase;
import org.activiti.rest.api.RestUrls;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
import org.restlet.data.Status;
import org.restlet.resource.ResourceException;
/**
......@@ -230,4 +234,118 @@ public class TaskQueryResourceTest extends BaseRestTestCase {
}
}
}
/**
* Test querying tasks using task and process variables. GET runtime/tasks
*/
@Deployment
public void testQueryTasksWithVariables() throws Exception {
// Task we're interested in
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess");
Task processTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
HashMap<String, Object> variables = new HashMap<String, Object>();
variables.put("stringVar", "Abcdef");
variables.put("intVar", 12345);
variables.put("booleanVar", true);
taskService.setVariablesLocal(processTask.getId(), variables);
// Additional tasks to confirm it's filtered out
runtimeService.startProcessInstanceByKey("oneTaskProcess");
ObjectNode requestNode = objectMapper.createObjectNode();
ArrayNode variableArray = objectMapper.createArrayNode();
ObjectNode variableNode = objectMapper.createObjectNode();
variableArray.add(variableNode);
requestNode.put("taskVariables", variableArray);
String url = RestUrls.createRelativeResourceUrl(RestUrls.URL_TASK_QUERY);
// String equals
variableNode.put("name", "stringVar");
variableNode.put("value", "Abcdef");
variableNode.put("operation", "equals");
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
// Integer equals
variableNode.removeAll();
variableNode.put("name", "intVar");
variableNode.put("value", 12345);
variableNode.put("operation", "equals");
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
// Boolean equals
variableNode.removeAll();
variableNode.put("name", "booleanVar");
variableNode.put("value", true);
variableNode.put("operation", "equals");
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
// String not equals
variableNode.removeAll();
variableNode.put("name", "stringVar");
variableNode.put("value", "ghijkl");
variableNode.put("operation", "notEquals");
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
// Integer not equals
variableNode.removeAll();
variableNode.put("name", "intVar");
variableNode.put("value", 45678);
variableNode.put("operation", "notEquals");
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
// Boolean not equals
variableNode.removeAll();
variableNode.put("name", "booleanVar");
variableNode.put("value", false);
variableNode.put("operation", "notEquals");
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
// String equals ignore case
variableNode.removeAll();
variableNode.put("name", "stringVar");
variableNode.put("value", "abCDEF");
variableNode.put("operation", "equalsIgnoreCase");
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
// String not equals ignore case
variableNode.removeAll();
variableNode.put("name", "stringVar");
variableNode.put("value", "HIJKLm");
variableNode.put("operation", "notEqualsIgnoreCase");
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
// String equals without value
variableNode.removeAll();
variableNode.put("value", "Abcdef");
variableNode.put("operation", "equals");
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
// Any other operation but equals without value
variableNode.removeAll();
variableNode.put("value", "abcdef");
variableNode.put("operation", "notEquals");
try {
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
fail("Exception expected");
} catch(ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, expected.getStatus());
assertEquals("Value-only query (without a variable-name) is only supported when using 'equals' operation.", expected.getStatus().getDescription());
}
// Illegal (but existing) operation
variableNode.removeAll();
variableNode.put("name", "stringVar");
variableNode.put("value", "abcdef");
variableNode.put("operation", "operationX");
try {
assertResultsPresentInDataResponse(url, requestNode, processTask.getId());
fail("Exception expected");
} catch(ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, expected.getStatus());
assertEquals("Unsupported variable query operation: operationX", expected.getStatus().getDescription());
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="OneTaskCategory">
<process id="oneTaskProcess" name="The One Task Process">
<documentation>One task process description</documentation>
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="processTask" />
<userTask id="processTask" name="Process task" activiti:candidateUsers="kermit" activiti:candidateGroups="sales">
<documentation>Process task description</documentation>
</userTask>
<sequenceFlow id="flow2" sourceRef="processTask" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
</definitions>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册