ALF-20190, ALF-20178 fixes for workflow rest api

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@56272 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Tijs Rademakers
2013-10-02 17:42:33 +00:00
parent 3e148f0b29
commit a402cc75ed
12 changed files with 826 additions and 156 deletions

View File

@@ -57,6 +57,7 @@ public class DeploymentsImpl extends WorkflowRestImpl implements Deployments
query.orderByDeploymenTime().desc();
List<org.activiti.engine.repository.Deployment> deployments = query.listPage(paging.getSkipCount(), paging.getMaxItems());
int totalCount = (int) query.count();
List<Deployment> page = new ArrayList<Deployment>(deployments.size());
for (org.activiti.engine.repository.Deployment deployment: deployments)
@@ -64,7 +65,7 @@ public class DeploymentsImpl extends WorkflowRestImpl implements Deployments
page.add(new Deployment(deployment));
}
return CollectionWithPagingInfo.asPaged(paging, page, false, page.size());
return CollectionWithPagingInfo.asPaged(paging, page, page.size() != totalCount, totalCount);
}
@Override

View File

@@ -224,6 +224,7 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD
List<org.activiti.engine.repository.ProcessDefinition> processDefinitions =
query.listPage(parameters.getPaging().getSkipCount(), parameters.getPaging().getMaxItems());
int totalCount = (int) query.count();
List<ProcessDefinition> page = new ArrayList<ProcessDefinition>(processDefinitions.size());
for (org.activiti.engine.repository.ProcessDefinition processDefinition: processDefinitions)
@@ -231,7 +232,7 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD
page.add(createProcessDefinitionRest((ProcessDefinitionEntity) processDefinition));
}
return CollectionWithPagingInfo.asPaged(parameters.getPaging(), page, false, page.size());
return CollectionWithPagingInfo.asPaged(parameters.getPaging(), page, page.size() != totalCount, totalCount);
}
@Override

View File

@@ -607,74 +607,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
if (taskAssociations.containsKey(propNameMap.get(variableName)))
{
AssociationDefinition associationDef = taskAssociations.get(propNameMap.get(variableName));
if (variableValue != null && ContentModel.TYPE_PERSON.equals(associationDef.getTargetClass().getName()))
{
if (associationDef.isTargetMany())
{
if (variableValue instanceof List<?>)
{
List<NodeRef> personList = new ArrayList<NodeRef>();
List<?> values = (List<?>) variableValue;
for (Object value : values)
{
NodeRef personRef = getPersonNodeRef(value.toString());
if (personRef == null)
{
throw new InvalidArgumentException(value.toString() + " is not a valid person user id");
}
personList.add(personRef);
}
variableValue = personList;
}
else
{
throw new InvalidArgumentException(variableName + " should have an array value");
}
}
else
{
NodeRef personRef = getPersonNodeRef(variableValue.toString());
if (personRef == null)
{
throw new InvalidArgumentException(variableValue.toString() + " is not a valid person user id");
}
variableValue = personRef;
}
}
else if (variableValue != null && ContentModel.TYPE_AUTHORITY_CONTAINER.equals(associationDef.getTargetClass().getName()))
{
if (associationDef.isTargetMany())
{
if (variableValue instanceof List<?>)
{
List<NodeRef> authorityList = new ArrayList<NodeRef>();
List<?> values = (List<?>) variableValue;
for (Object value : values)
{
NodeRef authorityRef = authorityService.getAuthorityNodeRef(value.toString());
if (authorityRef == null)
{
throw new InvalidArgumentException(value.toString() + " is not a valid authority id");
}
authorityList.add(authorityRef);
}
variableValue = authorityList;
}
else
{
throw new InvalidArgumentException(variableName + " should have an array value");
}
}
else
{
NodeRef authorityRef = authorityService.getAuthorityNodeRef(variableValue.toString());
if (authorityRef == null)
{
throw new InvalidArgumentException(variableValue.toString() + " is not a valid authority id");
}
variableValue = authorityRef;
}
}
variableValue = convertAssociationDefinitionValue(associationDef, variableName, variableValue);
}
else if (taskProperties.containsKey(propNameMap.get(variableName)))
{
@@ -921,7 +854,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new EntityNotFoundException(processId);
}
return updateVariableInProcess(processId, variable);
return updateVariableInProcess(processId, processInstance.getProcessDefinitionId(), variable);
}
@Override
@@ -944,21 +877,45 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
{
for (Variable variable : variables)
{
updatedVariables.add(updateVariableInProcess(processId, variable));
updatedVariables.add(updateVariableInProcess(processId, processInstance.getProcessDefinitionId(), variable));
}
}
return updatedVariables;
}
protected Variable updateVariableInProcess(String processId,Variable variable)
protected Variable updateVariableInProcess(String processId, String processDefinitionId, Variable variable)
{
if (variable.getName() == null)
{
throw new InvalidArgumentException("Variable name is required.");
}
// Get start-task definition for explicit typing of variables submitted at the start
String formKey = null;
StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(processDefinitionId);
if (startFormData != null)
{
formKey = startFormData.getFormKey();
}
DataTypeDefinition dataTypeDefinition = null;
if(variable.getType() != null)
TypeDefinition startTaskTypeDefinition = getWorkflowFactory().getTaskFullTypeDefinition(formKey, true);
TypeDefinitionContext context = new TypeDefinitionContext(startTaskTypeDefinition, getQNameConverter());
if (context.getPropertyDefinition(variable.getName()) != null)
{
dataTypeDefinition = context.getPropertyDefinition(variable.getName()).getDataType();
if (variable.getType() != null && dataTypeDefinition.getName().toPrefixString(namespaceService).equals(variable.getType()) == false) {
throw new InvalidArgumentException("type of variable " + variable.getName() + " should be " +
dataTypeDefinition.getName().toPrefixString(namespaceService));
}
}
else if (context.getAssociationDefinition(variable.getName()) != null)
{
dataTypeDefinition = dictionaryService.getDataType(DataTypeDefinition.NODE_REF);
}
if (dataTypeDefinition == null && variable.getType() != null)
{
try
{
@@ -970,13 +927,13 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new InvalidArgumentException("Unsupported type of variable: '" + variable.getType() +"'.");
}
}
else
else if (dataTypeDefinition == null)
{
// Fallback to raw value when no type has been passed and not present in model
dataTypeDefinition = dictionaryService.getDataType(restVariableHelper.extractTypeFromValue(variable.getValue()));
}
if(dataTypeDefinition == null)
if (dataTypeDefinition == null)
{
throw new InvalidArgumentException("Unsupported type of variable: '" + variable.getType() +"'.");
}
@@ -989,7 +946,15 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
}
else
{
actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, variable.getValue());
if (context.getAssociationDefinition(variable.getName()) != null)
{
actualValue = convertAssociationDefinitionValue(context.getAssociationDefinition(variable.getName()),
variable.getName(), variable.getValue());
}
else
{
actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, variable.getValue());
}
}
variable.setValue(actualValue);
@@ -1066,6 +1031,79 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
}
}
protected Object convertAssociationDefinitionValue(AssociationDefinition associationDef, String variableName, Object variableValue)
{
if (variableValue != null && ContentModel.TYPE_PERSON.equals(associationDef.getTargetClass().getName()))
{
if (associationDef.isTargetMany())
{
if (variableValue instanceof List<?>)
{
List<NodeRef> personList = new ArrayList<NodeRef>();
List<?> values = (List<?>) variableValue;
for (Object value : values)
{
NodeRef personRef = getPersonNodeRef(value.toString());
if (personRef == null)
{
throw new InvalidArgumentException(value.toString() + " is not a valid person user id");
}
personList.add(personRef);
}
variableValue = personList;
}
else
{
throw new InvalidArgumentException(variableName + " should have an array value");
}
}
else
{
NodeRef personRef = getPersonNodeRef(variableValue.toString());
if (personRef == null)
{
throw new InvalidArgumentException(variableValue.toString() + " is not a valid person user id");
}
variableValue = personRef;
}
}
else if (variableValue != null && ContentModel.TYPE_AUTHORITY_CONTAINER.equals(associationDef.getTargetClass().getName()))
{
if (associationDef.isTargetMany())
{
if (variableValue instanceof List<?>)
{
List<NodeRef> authorityList = new ArrayList<NodeRef>();
List<?> values = (List<?>) variableValue;
for (Object value : values)
{
NodeRef authorityRef = authorityService.getAuthorityNodeRef(value.toString());
if (authorityRef == null)
{
throw new InvalidArgumentException(value.toString() + " is not a valid authority id");
}
authorityList.add(authorityRef);
}
variableValue = authorityList;
}
else
{
throw new InvalidArgumentException(variableName + " should have an array value");
}
}
else
{
NodeRef authorityRef = authorityService.getAuthorityNodeRef(variableValue.toString());
if (authorityRef == null)
{
throw new InvalidArgumentException(variableValue.toString() + " is not a valid authority id");
}
variableValue = authorityRef;
}
}
return variableValue;
}
protected String getProcessDefinitionKey(String paramProcessDefinitionKey)
{
String processDefinitionKey = null;

View File

@@ -22,7 +22,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -94,13 +93,13 @@ public class RestVariableHelper
List<TaskVariable> result = new ArrayList<TaskVariable>();
if (localVariables != null && localVariables.size() > 0)
{
TypeDefinitionContext context = new TypeDefinitionContext(taskTypeDefinition);
TypeDefinitionContext context = new TypeDefinitionContext(taskTypeDefinition, getQNameConverter());
addTaskVariables(result, localVariables, context, VariableScope.LOCAL);
}
if (globalVariables != null && globalVariables.size() > 0)
{
TypeDefinitionContext context = new TypeDefinitionContext(startFormTypeDefinition);
TypeDefinitionContext context = new TypeDefinitionContext(startFormTypeDefinition, getQNameConverter());
addTaskVariables(result, globalVariables, context, VariableScope.GLOBAL);
}
@@ -115,7 +114,7 @@ public class RestVariableHelper
public List<Variable> getVariables(Map<String, Object> variables, TypeDefinition typeDefinition)
{
List<Variable> result = new ArrayList<Variable>();
TypeDefinitionContext context = new TypeDefinitionContext(typeDefinition);
TypeDefinitionContext context = new TypeDefinitionContext(typeDefinition, getQNameConverter());
Variable variable = null;
for(Entry<String, Object> entry : variables.entrySet())
@@ -372,40 +371,4 @@ public class RestVariableHelper
QName type = extractTypeFromValue(value);
return type.toPrefixString(namespaceService);
}
/**
* Helper contxt class used when checking variable types based on {@link TypeDefinition}.
*
* @author Frederik Heremans
*/
private class TypeDefinitionContext {
private Map<String, PropertyDefinition> propertyDefinitions;
private Map<String, AssociationDefinition> associationDefinitions;
public TypeDefinitionContext(TypeDefinition typeDefinition)
{
propertyDefinitions = new HashMap<String, PropertyDefinition>();
associationDefinitions = new HashMap<String, AssociationDefinition>();
for (Entry<QName, PropertyDefinition> entry : typeDefinition.getProperties().entrySet())
{
propertyDefinitions.put(getQNameConverter().mapQNameToName(entry.getKey()), entry.getValue());
}
for (Entry<QName, AssociationDefinition> entry : typeDefinition.getAssociations().entrySet())
{
associationDefinitions.put(getQNameConverter().mapQNameToName(entry.getKey()), entry.getValue());
}
}
public PropertyDefinition getPropertyDefinition(String rawVariableName)
{
return propertyDefinitions.get(rawVariableName);
}
public AssociationDefinition getAssociationDefinition(String rawVariableName)
{
return associationDefinitions.get(rawVariableName);
}
}
}

View File

@@ -36,6 +36,7 @@ import org.activiti.engine.task.DelegationState;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.IdentityLinkType;
import org.activiti.engine.task.TaskQuery;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.i18n.MessageService;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantUtil;
@@ -65,10 +66,11 @@ import org.alfresco.rest.workflow.api.model.TaskVariable;
import org.alfresco.rest.workflow.api.model.VariableScope;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.InvalidQNameException;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ISO8601DateFormat;
@@ -123,6 +125,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
private WorkflowObjectFactory workflowFactory;
private WorkflowQNameConverter qNameConverter;
private MessageService messageService;
private PersonService personService;
public void setRestVariableHelper(RestVariableHelper restVariableHelper)
{
@@ -134,6 +137,11 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
this.messageService = messageService;
}
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
@Override
public CollectionWithPagingInfo<Task> getTasks(Parameters parameters)
{
@@ -1054,9 +1062,63 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
{
throw new InvalidArgumentException("Variable scope is required and can only be 'local' or 'global'.");
}
DataTypeDefinition dataTypeDefinition = null;
if (taskVariable.getType() != null)
TypeDefinitionContext context = null;
if (taskVariable.getVariableScope() == VariableScope.GLOBAL)
{
// Get start-task definition for explicit typing of variables submitted at the start
String formKey = null;
StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(taskInstance.getProcessDefinitionId());
if (startFormData != null)
{
formKey = startFormData.getFormKey();
}
TypeDefinition startTaskTypeDefinition = getWorkflowFactory().getTaskFullTypeDefinition(formKey, true);
context = new TypeDefinitionContext(startTaskTypeDefinition, getQNameConverter());
if (context.getPropertyDefinition(taskVariable.getName()) != null)
{
dataTypeDefinition = context.getPropertyDefinition(taskVariable.getName()).getDataType();
if (taskVariable.getType() != null && dataTypeDefinition.getName().toPrefixString(namespaceService).equals(taskVariable.getType()) == false) {
throw new InvalidArgumentException("type of variable " + taskVariable.getName() + " should be " +
dataTypeDefinition.getName().toPrefixString(namespaceService));
}
}
else if (context.getAssociationDefinition(taskVariable.getName()) != null)
{
dataTypeDefinition = dictionaryService.getDataType(DataTypeDefinition.NODE_REF);
}
}
else
{
// Revert to either the content-model type or the raw type provided by the request
try
{
String formKey = activitiProcessEngine.getFormService().getTaskFormKey(taskInstance.getProcessDefinitionId(), taskInstance.getTaskDefinitionKey());
TypeDefinition typeDefinition = getWorkflowFactory().getTaskFullTypeDefinition(formKey, false);
context = new TypeDefinitionContext(typeDefinition, getQNameConverter());
if (context.getPropertyDefinition(taskVariable.getName()) != null)
{
dataTypeDefinition = context.getPropertyDefinition(taskVariable.getName()).getDataType();
if (taskVariable.getType() != null && dataTypeDefinition.getName().toPrefixString(namespaceService).equals(taskVariable.getType()) == false) {
throw new InvalidArgumentException("type of variable " + taskVariable.getName() + " should be " +
dataTypeDefinition.getName().toPrefixString(namespaceService));
}
}
else if (context.getAssociationDefinition(taskVariable.getName()) != null)
{
dataTypeDefinition = dictionaryService.getDataType(DataTypeDefinition.NODE_REF);
}
}
catch (InvalidQNameException ignore)
{
// In case the property is not part of the model, it's possible that the property-name is not a valid.
// This can be ignored safeley as it falls back to the raw type
}
}
if (dataTypeDefinition == null && taskVariable.getType() != null)
{
try
{
@@ -1067,41 +1129,11 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
{
throw new InvalidArgumentException("Unsupported type of variable: '" + taskVariable.getType() +"'.");
}
}
else
}
else if (dataTypeDefinition == null)
{
// Revert to either the content-model type or the raw type provided by the request
try
{
String formKey = activitiProcessEngine.getFormService().getTaskFormKey(taskInstance.getProcessDefinitionId(), taskInstance.getTaskDefinitionKey());
TypeDefinition typeDefinition = getWorkflowFactory().getTaskFullTypeDefinition(formKey, false);
QName propQName = WorkflowQNameConverter.convertNameToQName(taskVariable.getName(), namespaceService);
PropertyDefinition propDef = typeDefinition.getProperties().get(propQName);
if (propDef != null)
{
dataTypeDefinition = propDef.getDataType();
}
else
{
AssociationDefinition assocDef = typeDefinition.getAssociations().get(propQName);
if(assocDef != null)
{
dataTypeDefinition = dictionaryService.getDataType(DataTypeDefinition.NODE_REF);
}
}
}
catch (InvalidQNameException ignore)
{
// In case the property is not part of the model, it's possible that the property-name is not a valid.
// This can be ignored safeley as it falls back to the raw type
}
if (dataTypeDefinition == null)
{
// Final fallback to raw value when no type has been passed and not present in model
dataTypeDefinition = dictionaryService.getDataType(restVariableHelper.extractTypeFromValue(taskVariable.getValue()));
}
// Final fallback to raw value when no type has been passed and not present in model
dataTypeDefinition = dictionaryService.getDataType(restVariableHelper.extractTypeFromValue(taskVariable.getValue()));
}
if (dataTypeDefinition == null)
@@ -1117,7 +1149,15 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
}
else
{
actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, taskVariable.getValue());
if (context != null && context.getAssociationDefinition(taskVariable.getName()) != null)
{
actualValue = convertAssociationDefinitionValue(context.getAssociationDefinition(taskVariable.getName()),
taskVariable.getName(), taskVariable.getValue());
}
else
{
actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, taskVariable.getValue());
}
}
taskVariable.setValue(actualValue);
@@ -1556,6 +1596,92 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
}
}
protected Object convertAssociationDefinitionValue(AssociationDefinition associationDef, String variableName, Object variableValue)
{
if (variableValue != null && ContentModel.TYPE_PERSON.equals(associationDef.getTargetClass().getName()))
{
if (associationDef.isTargetMany())
{
if (variableValue instanceof List<?>)
{
List<NodeRef> personList = new ArrayList<NodeRef>();
List<?> values = (List<?>) variableValue;
for (Object value : values)
{
NodeRef personRef = getPersonNodeRef(value.toString());
if (personRef == null)
{
throw new InvalidArgumentException(value.toString() + " is not a valid person user id");
}
personList.add(personRef);
}
variableValue = personList;
}
else
{
throw new InvalidArgumentException(variableName + " should have an array value");
}
}
else
{
NodeRef personRef = getPersonNodeRef(variableValue.toString());
if (personRef == null)
{
throw new InvalidArgumentException(variableValue.toString() + " is not a valid person user id");
}
variableValue = personRef;
}
}
else if (variableValue != null && ContentModel.TYPE_AUTHORITY_CONTAINER.equals(associationDef.getTargetClass().getName()))
{
if (associationDef.isTargetMany())
{
if (variableValue instanceof List<?>)
{
List<NodeRef> authorityList = new ArrayList<NodeRef>();
List<?> values = (List<?>) variableValue;
for (Object value : values)
{
NodeRef authorityRef = authorityService.getAuthorityNodeRef(value.toString());
if (authorityRef == null)
{
throw new InvalidArgumentException(value.toString() + " is not a valid authority id");
}
authorityList.add(authorityRef);
}
variableValue = authorityList;
}
else
{
throw new InvalidArgumentException(variableName + " should have an array value");
}
}
else
{
NodeRef authorityRef = authorityService.getAuthorityNodeRef(variableValue.toString());
if (authorityRef == null)
{
throw new InvalidArgumentException(variableValue.toString() + " is not a valid authority id");
}
variableValue = authorityRef;
}
}
return variableValue;
}
protected NodeRef getPersonNodeRef(String name)
{
NodeRef authority = null;
if (name != null)
{
if (personService.personExists(name))
{
authority = personService.getPerson(name);
}
}
return authority;
}
protected WorkflowQNameConverter getQNameConverter()
{
if (qNameConverter == null)

View File

@@ -0,0 +1,48 @@
package org.alfresco.rest.workflow.api.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.alfresco.repo.workflow.WorkflowQNameConverter;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.namespace.QName;
/**
* Helper contxt class used when checking variable types based on {@link TypeDefinition}.
*
* @author Frederik Heremans
*/
public class TypeDefinitionContext {
private Map<String, PropertyDefinition> propertyDefinitions;
private Map<String, AssociationDefinition> associationDefinitions;
public TypeDefinitionContext(TypeDefinition typeDefinition, WorkflowQNameConverter qNameConverter)
{
propertyDefinitions = new HashMap<String, PropertyDefinition>();
associationDefinitions = new HashMap<String, AssociationDefinition>();
for (Entry<QName, PropertyDefinition> entry : typeDefinition.getProperties().entrySet())
{
propertyDefinitions.put(qNameConverter.mapQNameToName(entry.getKey()), entry.getValue());
}
for (Entry<QName, AssociationDefinition> entry : typeDefinition.getAssociations().entrySet())
{
associationDefinitions.put(qNameConverter.mapQNameToName(entry.getKey()), entry.getValue());
}
}
public PropertyDefinition getPropertyDefinition(String rawVariableName)
{
return propertyDefinitions.get(rawVariableName);
}
public AssociationDefinition getAssociationDefinition(String rawVariableName)
{
return associationDefinitions.get(rawVariableName);
}
}