SHA-1598: Added support to Get Task Instances API to filter result, based on the given property.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@130404 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jamal Kaabi-Mofrad
2016-09-07 13:06:32 +00:00
parent 59eed12c13
commit f46962577f
3 changed files with 190 additions and 67 deletions

View File

@@ -4,7 +4,7 @@
Lists all Workflow Task Instances associated with an authority and of a given State. Lists all Workflow Task Instances associated with an authority and of a given State.
The list of returned tasks also includes pooled tasks which the specified authority is eligible to claim. The list of returned tasks also includes pooled tasks which the specified authority is eligible to claim.
</description> </description>
<url>/api/task-instances?authority={authority?}&amp;state={state?}&amp;priority={priority?}&amp;pooledTasks={pooledTasks?}&amp;dueBefore={dueBefore?}&amp;dueAfter={dueAfter?}&amp;properties={properties?}&amp;maxItems={maxItems?}&amp;skipCount={skipCount?}&amp;exclude={exclude?}</url> <url>/api/task-instances?authority={authority?}&amp;state={state?}&amp;priority={priority?}&amp;pooledTasks={pooledTasks?}&amp;dueBefore={dueBefore?}&amp;dueAfter={dueAfter?}&amp;properties={properties?}&amp;maxItems={maxItems?}&amp;skipCount={skipCount?}&amp;exclude={exclude?}&amp;property={propQName/propValue?}</url>
<url>/api/workflow-instances/{workflow_instance_id}/task-instances?authority={authority?}&amp;state={state?}&amp;priority={priority?}&amp;dueBefore={isoDate?}&amp;dueAfter={isoDate?}&amp;properties={prop1, prop2, prop3...?}&amp;maxItems={maxItems?}&amp;skipCount={skipCount?}&amp;exclude={exclude?}</url> <url>/api/workflow-instances/{workflow_instance_id}/task-instances?authority={authority?}&amp;state={state?}&amp;priority={priority?}&amp;dueBefore={isoDate?}&amp;dueAfter={isoDate?}&amp;properties={prop1, prop2, prop3...?}&amp;maxItems={maxItems?}&amp;skipCount={skipCount?}&amp;exclude={exclude?}</url>
<format default="json"/> <format default="json"/>
<authentication>user</authentication> <authentication>user</authentication>
@@ -55,6 +55,10 @@
<shortname>workflow_instance_id</shortname> <shortname>workflow_instance_id</shortname>
<description>Restricts the returned tasks to those that belong to the given workflow process instance id.</description> <description>Restricts the returned tasks to those that belong to the given workflow process instance id.</description>
</arg> </arg>
<arg>
<shortname>property</shortname>
<description>Restricts the returned tasks to only those that match the given property. The property name should be a valid QName format followed by '/' then the property value. E.g. bpm:description/myDescription</description>
</arg>
</args> </args>
<responses> <responses>
<response> <response>

View File

@@ -25,6 +25,7 @@
*/ */
package org.alfresco.repo.web.scripts.workflow; package org.alfresco.repo.web.scripts.workflow;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@@ -41,6 +42,8 @@ import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskQuery; import org.alfresco.service.cmr.workflow.WorkflowTaskQuery;
import org.alfresco.service.cmr.workflow.WorkflowTaskQuery.OrderBy; import org.alfresco.service.cmr.workflow.WorkflowTaskQuery.OrderBy;
import org.alfresco.service.cmr.workflow.WorkflowTaskState; import org.alfresco.service.cmr.workflow.WorkflowTaskState;
import org.alfresco.service.namespace.NamespaceException;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ModelUtil; import org.alfresco.util.ModelUtil;
import org.springframework.extensions.webscripts.Cache; import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.Status;
@@ -63,6 +66,7 @@ public class TaskInstancesGet extends AbstractWorkflowWebscript
public static final String PARAM_DUE_AFTER = "dueAfter"; public static final String PARAM_DUE_AFTER = "dueAfter";
public static final String PARAM_PROPERTIES = "properties"; public static final String PARAM_PROPERTIES = "properties";
public static final String PARAM_POOLED_TASKS = "pooledTasks"; public static final String PARAM_POOLED_TASKS = "pooledTasks";
public static final String PARAM_PROPERTY = "property";
public static final String VAR_WORKFLOW_INSTANCE_ID = "workflow_instance_id"; public static final String VAR_WORKFLOW_INSTANCE_ID = "workflow_instance_id";
private WorkflowTaskDueAscComparator taskComparator = new WorkflowTaskDueAscComparator(); private WorkflowTaskDueAscComparator taskComparator = new WorkflowTaskDueAscComparator();
@@ -96,6 +100,7 @@ public class TaskInstancesGet extends AbstractWorkflowWebscript
// get filter param values // get filter param values
filters.put(PARAM_PRIORITY, req.getParameter(PARAM_PRIORITY)); filters.put(PARAM_PRIORITY, req.getParameter(PARAM_PRIORITY));
filters.put(PARAM_PROPERTY, req.getParameter(PARAM_PROPERTY));
processDateFilter(req, PARAM_DUE_BEFORE, filters); processDateFilter(req, PARAM_DUE_BEFORE, filters);
processDateFilter(req, PARAM_DUE_AFTER, filters); processDateFilter(req, PARAM_DUE_AFTER, filters);
@@ -179,20 +184,18 @@ public class TaskInstancesGet extends AbstractWorkflowWebscript
ArrayList<Map<String, Object>> results = new ArrayList<Map<String, Object>>(); ArrayList<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
// Filter results // Filter results
WorkflowTask task = null; for (WorkflowTask task : allTasks)
for(int i=0; i<allTasks.size(); i++)
{ {
task = allTasks.get(i); if (matches(task, filters))
if (matches(task, filters))
{ {
// Total-count needs to be based on matching tasks only, so we can't just use allTasks.size() for this // Total-count needs to be based on matching tasks only, so we can't just use allTasks.size() for this
totalCount++; totalCount++;
if(totalCount > skipCount && (maxItems < 0 || maxItems > results.size())) if(totalCount > skipCount && (maxItems < 0 || maxItems > results.size()))
{ {
// Only build the actual detail if it's in the range of items we need. This will // Only build the actual detail if it's in the range of items we need. This will
// drastically improve performance over paging after building the model // drastically improve performance over paging after building the model
results.add(modelBuilder.buildSimple(task, properties)); results.add(modelBuilder.buildSimple(task, properties));
} }
} }
} }
@@ -341,6 +344,29 @@ public class TaskInstancesGet extends AbstractWorkflowWebscript
break; break;
} }
} }
else if(key.equals(PARAM_PROPERTY))
{
String[] propertyValuePair = filterValue.toString().split("/");
if (propertyValuePair.length != 2)
{
break;
}
QName propertyQName;
try
{
propertyQName = QName.createQName(propertyValuePair[0], namespaceService);
}
catch (NamespaceException ne)
{
break;
}
Serializable value = task.getProperties().get(propertyQName);
if (value != null && !value.equals(propertyValuePair[1]))
{
result = false;
break;
}
}
} }
} }

View File

@@ -306,6 +306,89 @@ public abstract class AbstractWorkflowRestApiTest extends BaseWebScriptTest
assertEquals(0, resultArray.length()); assertEquals(0, resultArray.length());
} }
public void testTaskInstancesGetWithFiltering() throws Exception
{
// Check USER2 starts with no tasks.
personManager.setUser(USER2);
Response response = sendRequest(new GetRequest(MessageFormat.format(URL_USER_TASKS, USER2)), 200);
getJsonArray(response, 0);
// Start workflow as USER1 and assign the task to GROUP.
personManager.setUser(USER1);
WorkflowDefinition wfDefinition = workflowService.getDefinitionByName(getReviewPooledWorkflowDefinitionName());
Map<QName, Serializable> params = new HashMap<>(3);
params.put(WorkflowModel.ASSOC_GROUP_ASSIGNEE, groupManager.get(GROUP));
params.put(WorkflowModel.ASSOC_PACKAGE, packageRef);
params.put(WorkflowModel.PROP_WORKFLOW_DESCRIPTION, "descTest1");
WorkflowPath wfPath = workflowService.startWorkflow(wfDefinition.getId(), params);
String workflowId = wfPath.getInstance().getId();
workflows.add(workflowId);
WorkflowTask startTask = workflowService.getStartTask(workflowId);
workflowService.endTask(startTask.getId(), null);
// Start another workflow as USER1 and assign the task to GROUP.
wfDefinition = workflowService.getDefinitionByName(getReviewPooledWorkflowDefinitionName());
params.put(WorkflowModel.ASSOC_GROUP_ASSIGNEE, groupManager.get(GROUP));
params.put(WorkflowModel.ASSOC_PACKAGE, workflowService.createPackage(null));
params.put(WorkflowModel.PROP_WORKFLOW_DESCRIPTION, "descTest2");
wfPath = workflowService.startWorkflow(wfDefinition.getId(), params);
workflowId = wfPath.getInstance().getId();
workflows.add(workflowId);
startTask = workflowService.getStartTask(workflowId);
workflowService.endTask(startTask.getId(), null);
// Check USER2's tasks without filtering. It should return two tasks as USER2 is a member of the GROUP
personManager.setUser(USER2);
response = sendRequest(new GetRequest(MessageFormat.format(URL_USER_TASKS, USER2)), 200);
getJsonArray(response, 2);
//Check USER2's tasks With filtering where property bpm:description should match "descTest1"
response = sendRequest(new GetRequest(MessageFormat.format(URL_USER_TASKS, USER2) + "&property=bpm:description/descTest1"), 200);
JSONArray results = getJsonArray(response, 1);
JSONObject result = results.getJSONObject(0);
assertNotNull(result);
JSONObject properties = result.getJSONObject("properties");
assertNotNull(properties);
assertEquals("descTest1", properties.getString("bpm_description"));
//Check USER2's tasks With filtering where property bpm:description should match "descTest2"
response = sendRequest(new GetRequest(MessageFormat.format(URL_USER_TASKS, USER2) + "&property=bpm:description/descTest2"), 200);
results = getJsonArray(response, 1);
result = results.getJSONObject(0);
assertNotNull(result);
properties = result.getJSONObject("properties");
assertNotNull(properties);
assertEquals("descTest2", properties.getString("bpm_description"));
/*
* -ve tests
*/
// Mismatched property value - There is no task with the description "somePropValue"
response = sendRequest(new GetRequest(MessageFormat.format(URL_USER_TASKS, USER2) + "&property=bpm:description/somePropValue"), 200);
getJsonArray(response, 0);
//Unregistered namespace prefix (ignores "property" parameter)
response = sendRequest(new GetRequest(MessageFormat.format(URL_USER_TASKS, USER2) + "&property=unknownPrefix:description/test"), 200);
getJsonArray(response, 2);
// Nonexistent property (ignores "property" parameter)
response = sendRequest(new GetRequest(MessageFormat.format(URL_USER_TASKS, USER2) + "&property=bpm:nonexistentProp/test"), 200);
getJsonArray(response, 2);
// Not well-formed parameter
response = sendRequest(new GetRequest(MessageFormat.format(URL_USER_TASKS, USER2) + "&property=bpm:description/"), 200);
getJsonArray(response, 2);
// Check USER3's tasks without filtering. It should return 0 task as USER3 is not a member of the GROUP
personManager.setUser(USER3);
response = sendRequest(new GetRequest(MessageFormat.format(URL_USER_TASKS, USER3)), 200);
getJsonArray(response, 0);
}
public void testWorkflowPermissions() throws Exception public void testWorkflowPermissions() throws Exception
{ {
// Start workflow as USER1 and assign task to USER1. // Start workflow as USER1 and assign task to USER1.
@@ -1786,6 +1869,16 @@ public abstract class AbstractWorkflowRestApiTest extends BaseWebScriptTest
assertEquals(skipCount, paging.getInt("skipCount")); assertEquals(skipCount, paging.getInt("skipCount"));
} }
private JSONArray getJsonArray(Response response, int expectedLength) throws Exception
{
String jsonStr = response.getContentAsString();
JSONObject json = new JSONObject(jsonStr);
JSONArray results = json.getJSONArray("data");
assertNotNull(results);
assertEquals(expectedLength, results.length());
return results;
}
protected abstract String getEngine(); protected abstract String getEngine();
} }