From 9309ed04f596589ae7be721f2d84ec7296241930 Mon Sep 17 00:00:00 2001 From: Tijs Rademakers Date: Tue, 17 Sep 2013 15:55:22 +0000 Subject: [PATCH] Workflow REST API fixes for variable query git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@55420 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../api/impl/MapBasedQueryWalker.java | 64 ++++++++++++------- .../api/impl/TaskVariablesWalkerCallback.java | 6 +- .../rest/workflow/api/impl/TasksImpl.java | 26 +++++--- .../workflow/api/model/VariableScope.java | 3 +- .../api/tests/TaskWorkflowApiTest.java | 20 ++++++ 5 files changed, 84 insertions(+), 35 deletions(-) diff --git a/source/java/org/alfresco/rest/workflow/api/impl/MapBasedQueryWalker.java b/source/java/org/alfresco/rest/workflow/api/impl/MapBasedQueryWalker.java index 8112409a1c..e5dabcb6e1 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/MapBasedQueryWalker.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/MapBasedQueryWalker.java @@ -29,10 +29,12 @@ import org.alfresco.rest.antlr.WhereClauseParser; import org.alfresco.rest.framework.core.exceptions.ApiException; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.resource.parameters.where.QueryHelper.WalkerCallbackAdapter; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.alfresco.util.ISO8601DateFormat; import org.apache.commons.beanutils.ConversionException; import org.apache.commons.beanutils.ConvertUtils; @@ -151,7 +153,11 @@ public class MapBasedQueryWalker extends WalkerCallbackAdapter { throw new InvalidArgumentException("Cannot use negated matching for property: " + property); } - if (supportedMatchesParameters != null && supportedMatchesParameters.contains(property)) + if (variablesEnabled && property.startsWith("variables/")) + { + processVariable(property, value, WhereClauseParser.MATCHES); + } + else if (supportedMatchesParameters != null && supportedMatchesParameters.contains(property)) { matchesProperties.put(property, value); } @@ -168,27 +174,7 @@ public class MapBasedQueryWalker extends WalkerCallbackAdapter if (variablesEnabled && propertyName.startsWith("variables/")) { - String localPropertyName = propertyName.replaceFirst("variables/", ""); - Object actualValue = null; - if ((propertyValue.contains("_") || propertyValue.contains(":")) && propertyValue.contains(" ")) - { - String typeDef = propertyValue.substring(0, propertyValue.indexOf(' ')); - try - { - QName dataType = QName.createQName(typeDef.replace('_', ':'), namespaceService); - actualValue = DefaultTypeConverter.INSTANCE.convert(dictionaryService.getDataType(dataType), - propertyValue.substring(propertyValue.indexOf(' ') + 1)); - } - catch (Exception e) - { - throw new ApiException("Error translating propertyName " + propertyName + " with value " + propertyValue); - } - } - else - { - actualValue = propertyValue; - } - variableProperties.add(new QueryVariableHolder(localPropertyName, type, actualValue)); + processVariable(propertyName, propertyValue, type); } else { @@ -346,6 +332,40 @@ public class MapBasedQueryWalker extends WalkerCallbackAdapter // method indicates that AND is // supported. OR is not supported at the same time. } + + protected void processVariable(String propertyName, String propertyValue, int type) + { + String localPropertyName = propertyName.replaceFirst("variables/", ""); + Object actualValue = null; + if ((propertyValue.contains("_") || propertyValue.contains(":")) && propertyValue.contains(" ")) + { + String typeDef = propertyValue.substring(0, propertyValue.indexOf(' ')); + try + { + QName dataType = QName.createQName(typeDef.replace('_', ':'), namespaceService); + DataTypeDefinition dataTypeDefinition = dictionaryService.getDataType(dataType); + if (dataTypeDefinition != null && "java.util.Date".equalsIgnoreCase(dataTypeDefinition.getJavaClassName())) + { + // fix for different ISO 8601 Date format classes in Alfresco (org.alfresco.util and Spring Surf) + actualValue = ISO8601DateFormat.parse(propertyValue.substring(propertyValue.indexOf(' ') + 1)); + } + else + { + actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, + propertyValue.substring(propertyValue.indexOf(' ') + 1)); + } + } + catch (Exception e) + { + throw new ApiException("Error translating propertyName " + propertyName + " with value " + propertyValue); + } + } + else + { + actualValue = propertyValue; + } + variableProperties.add(new QueryVariableHolder(localPropertyName, type, actualValue)); + } /** * Called when unsupported property is encountered or comparison operator diff --git a/source/java/org/alfresco/rest/workflow/api/impl/TaskVariablesWalkerCallback.java b/source/java/org/alfresco/rest/workflow/api/impl/TaskVariablesWalkerCallback.java index 4c2ad61282..c2f5870d0a 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/TaskVariablesWalkerCallback.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/TaskVariablesWalkerCallback.java @@ -32,15 +32,15 @@ public class TaskVariablesWalkerCallback extends WalkerCallbackAdapter @Override public void comparison(int type, String propertyName, String propertyValue) { - if(PROPERTY_SCOPE.equals(propertyName)) + if (PROPERTY_SCOPE.equals(propertyName)) { - if(type != WhereClauseParser.EQUALS) + if (type != WhereClauseParser.EQUALS) { throw new InvalidQueryException("Only equals is allowed for 'scope' comparison."); } scope = VariableScope.getScopeForValue(propertyValue); - if(scope == null) + if (scope == null) { throw new InvalidQueryException("Invalid value for 'scope' used in query: " + propertyValue + "."); } diff --git a/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java index 6120a4cd45..b78aa4fb41 100644 --- a/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java +++ b/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java @@ -87,12 +87,12 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks private static final Set TASK_COLLECTION_EQUALS_QUERY_PROPERTIES = new HashSet(Arrays.asList( "status", "assignee", "owner", "candidateUser", "candidateGroup", "name", "description", "priority", "processId", - "processBusinessKey", "activityDefinitionId", "processDefinitionId", "processDefinitionName", "startedAt", "endedAt", "dueAt", - "includeTaskVariables", "includeProcessVariables" + "processBusinessKey", "activityDefinitionId", "processDefinitionId", "processDefinitionKey", "processDefinitionName", "startedAt", + "endedAt", "dueAt", "includeTaskVariables", "includeProcessVariables" )); private static final Set TASK_COLLECTION_MATCHES_QUERY_PROPERTIES = new HashSet(Arrays.asList( - "assignee", "owner", "name", "description", "processBusinessKey", "activityDefinitionId", "processDefinitionName" + "assignee", "owner", "name", "description", "processBusinessKey", "activityDefinitionId", "processDefinitionKey", "processDefinitionName" )); private static final Set TASK_COLLECTION_GREATERTHAN_QUERY_PROPERTIES = new HashSet(Arrays.asList( @@ -172,6 +172,8 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks String activityDefinitionId = propertyWalker.getProperty("activityDefinitionId", WhereClauseParser.EQUALS); String activityDefinitionIdLike = propertyWalker.getProperty("activityDefinitionId", WhereClauseParser.MATCHES); String processDefinitionId = propertyWalker.getProperty("processDefinitionId", WhereClauseParser.EQUALS); + String processDefinitionKey = propertyWalker.getProperty("processDefinitionKey", WhereClauseParser.EQUALS); + String processDefinitionKeyLike = propertyWalker.getProperty("processDefinitionKey", WhereClauseParser.MATCHES); String processDefinitionName = propertyWalker.getProperty("processDefinitionName", WhereClauseParser.EQUALS); String processDefinitionNameLike = propertyWalker.getProperty("processDefinitionName", WhereClauseParser.MATCHES); Date startedAt = propertyWalker.getProperty("startedAt", WhereClauseParser.EQUALS, Date.class); @@ -247,6 +249,8 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks if (activityDefinitionId != null) query.taskDefinitionKey(activityDefinitionId); if (activityDefinitionIdLike != null) query.taskDefinitionKey(activityDefinitionIdLike); if (processDefinitionId != null) query.processDefinitionId(processDefinitionId); + if (processDefinitionKey != null) query.processDefinitionKey(processDefinitionKey); + if (processDefinitionKeyLike != null) query.processDefinitionKeyLike(processDefinitionKeyLike); if (processDefinitionName != null) query.processDefinitionName(processDefinitionName); if (processDefinitionNameLike != null) query.processDefinitionNameLike(processDefinitionNameLike); if (dueAt != null) query.dueDate(dueAt); @@ -372,6 +376,8 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks if (activityDefinitionId != null) query.taskDefinitionKey(activityDefinitionId); if (activityDefinitionIdLike != null) query.taskDefinitionKey(activityDefinitionIdLike); if (processDefinitionId != null) query.processDefinitionId(processDefinitionId); + if (processDefinitionKey != null) query.processDefinitionKey(processDefinitionKey); + if (processDefinitionKeyLike != null) query.processDefinitionKeyLike(processDefinitionKeyLike); if (processDefinitionName != null) query.processDefinitionName(processDefinitionName); if (processDefinitionNameLike != null) query.processDefinitionNameLike(processDefinitionNameLike); if (dueAt != null) query.taskDueDate(dueAt); @@ -647,19 +653,21 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks // In case the action is claim, we gather all candidate groups for this tasks, since we already have // the identity-links, there is no reason why we should check candidate using a DB-query - for(IdentityLink link : linksForTask) { - if(user.equals(link.getUserId()) && IdentityLinkType.STARTER.equals(link.getType())) + for (IdentityLink link : linksForTask) + { + if (user.equals(link.getUserId()) && IdentityLinkType.STARTER.equals(link.getType())) { authorized = true; break; } - if(taskAction == TaskStateTransition.CLAIMED && link.getGroupId() != null && link.getType().equals(IdentityLinkType.CANDIDATE)) { + if (taskAction == TaskStateTransition.CLAIMED && link.getGroupId() != null && link.getType().equals(IdentityLinkType.CANDIDATE)) + { candidateGroups.add(link.getGroupId()); } - if(taskAction == TaskStateTransition.CLAIMED && + if (taskAction == TaskStateTransition.CLAIMED && link.getUserId() != null && link.getType().equals(IdentityLinkType.CANDIDATE) && - user.equals(link.getUserId())) { - + user.equals(link.getUserId())) + { // User is a direct candidate for the task, authorized to claim authorized = true; break; diff --git a/source/java/org/alfresco/rest/workflow/api/model/VariableScope.java b/source/java/org/alfresco/rest/workflow/api/model/VariableScope.java index 7b37b3de74..8aab463f48 100644 --- a/source/java/org/alfresco/rest/workflow/api/model/VariableScope.java +++ b/source/java/org/alfresco/rest/workflow/api/model/VariableScope.java @@ -34,7 +34,8 @@ public enum VariableScope * a valid scope. */ public static VariableScope getScopeForValue(String scopeValue) { - for(VariableScope scope : values()) { + for(VariableScope scope : values()) + { if(scope.getValue().equals(scopeValue)) { return scope; diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java b/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java index 4a5dbe4394..571e41b024 100644 --- a/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java +++ b/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java @@ -1456,6 +1456,14 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi params.put("where", "(status = 'any' AND processBusinessKey = '" + businessKey + "')"); assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId()); + params.clear(); + params.put("where", "(status = 'any' AND processBusinessKey MATCHES('" + businessKey + "'))"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId()); + + params.clear(); + params.put("where", "(status = 'any' AND processBusinessKey MATCHES('" + businessKey.substring(0, businessKey.length() - 2) + "%'))"); + assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId()); + // Activity definition id filtering params.clear(); params.put("where", "(status = 'active' AND activityDefinitionId = 'verifyTaskDone' AND processId='" + processInstance.getId() +"')"); @@ -1563,6 +1571,18 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi params.put("where", "(variables/numberVar < 'd:int 10')"); assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); + params.clear(); + params.put("where", "(variables/bpm_dueDate = 'd:datetime " + ISO8601DateFormat.format(new Date()) + "')"); + assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); + + params.clear(); + params.put("where", "(variables/bpm_dueDate = 'd:datetime 2013-09-15T12:22:31.866+0000')"); + assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); + + params.clear(); + params.put("where", "(variables/bpm_comment MATCHES ('test%'))"); + assertEquals(0, getResultSizeForTaskQuery(params, tasksClient)); + // test with OR operator params.clear(); params.put("where", "(status = 'any' OR candidateGroup = 'sales')");