Merged HEAD-QA to HEAD (4.2) - final one

r54310-54386


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@54387 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Samuel Langlois
2013-08-22 08:25:02 +00:00
parent 150d9784e0
commit 5416d83ac2
51 changed files with 2907 additions and 399 deletions

View File

@@ -0,0 +1,10 @@
package org.alfresco.rest.workflow.api;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.workflow.api.model.Activity;
public interface Activities
{
CollectionWithPagingInfo<Activity> getActivities(String processId, Parameters parameters);
}

View File

@@ -18,11 +18,12 @@
*/
package org.alfresco.rest.workflow.api;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.workflow.api.model.ProcessDefinition;
import org.alfresco.rest.workflow.api.model.FormModelElement;
import org.alfresco.rest.workflow.api.model.ProcessDefinition;
public interface ProcessDefinitions
{
@@ -30,5 +31,7 @@ public interface ProcessDefinitions
public ProcessDefinition getProcessDefinition(String definitionId);
public BinaryResource getProcessDefinitionImage(String definitionId);
public CollectionWithPagingInfo<FormModelElement> getStartFormModel(String definitionId, Paging paging);
}

View File

@@ -18,6 +18,8 @@
*/
package org.alfresco.rest.workflow.api;
import java.util.List;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
@@ -47,6 +49,8 @@ public interface Processes
CollectionWithPagingInfo<Variable> getVariables(String processId, Paging paging);
Variable updateVariable(String processId, Variable entity);
List<Variable> updateVariables(String processId, List<Variable> variables);
void deleteVariable(String processId, String id);

View File

@@ -18,6 +18,8 @@
*/
package org.alfresco.rest.workflow.api;
import java.util.List;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
@@ -26,11 +28,14 @@ import org.alfresco.rest.workflow.api.model.Item;
import org.alfresco.rest.workflow.api.model.Task;
import org.alfresco.rest.workflow.api.model.TaskCandidate;
import org.alfresco.rest.workflow.api.model.TaskVariable;
import org.alfresco.rest.workflow.api.model.Variable;
import org.alfresco.rest.workflow.api.model.VariableScope;
public interface Tasks
{
CollectionWithPagingInfo<Task> getTasks(Parameters parameters);
CollectionWithPagingInfo<Task> getTasks(String processId, Parameters parameters);
Task getTask(String taskId);
@@ -44,6 +49,8 @@ public interface Tasks
CollectionWithPagingInfo<TaskVariable> getTaskVariables(String taskId, Paging paging, VariableScope scope);
TaskVariable updateTaskVariable(String taskId, TaskVariable taskVariable);
List<TaskVariable> updateTaskVariables(String taskId, List<TaskVariable> variables);
void deleteTaskVariable(String taskId, String variableName);

View File

@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
@WebApi(name="alfresco", scope=Api.SCOPE.PUBLIC, version=1)
@WebApi(name="workflow", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rest.workflow.api.deployments;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;

View File

@@ -0,0 +1,50 @@
package org.alfresco.rest.workflow.api.impl;
import java.util.ArrayList;
import java.util.List;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.workflow.api.Activities;
import org.alfresco.rest.workflow.api.model.Activity;
public class ActivitiesImpl extends WorkflowRestImpl implements Activities
{
private static final String STATUS_ACTIVE = "active";
private static final String STATUS_COMPLETED = "completed";
@Override
public CollectionWithPagingInfo<Activity> getActivities(String processId, Parameters parameters)
{
Paging paging = parameters.getPaging();
String status = parameters.getParameter("status");
validateIfUserAllowedToWorkWithProcess(processId);
HistoricActivityInstanceQuery query = activitiProcessEngine
.getHistoryService()
.createHistoricActivityInstanceQuery();
if (STATUS_ACTIVE.equals(status)) query.unfinished();
else if (STATUS_COMPLETED.equals(status)) query.finished();
query.processInstanceId(processId);
query.orderByExecutionId().asc();
List<HistoricActivityInstance> activities = query.listPage(paging.getSkipCount(), paging.getMaxItems());
List<Activity> page = new ArrayList<Activity>(activities.size());
for (HistoricActivityInstance activityInstance: activities)
{
Activity activity = new Activity(activityInstance);
page.add(activity);
}
return CollectionWithPagingInfo.asPaged(paging, page, false, page.size());
}
}

View File

@@ -170,7 +170,7 @@ public class MapBasedQueryWalker extends WalkerCallbackAdapter
{
String localPropertyName = propertyName.replaceFirst("variables/", "");
Object actualValue = null;
if (propertyValue.contains("_") && propertyValue.contains(" "))
if ((propertyValue.contains("_") || propertyValue.contains(":")) && propertyValue.contains(" "))
{
String typeDef = propertyValue.substring(0, propertyValue.indexOf(' '));
try

View File

@@ -18,13 +18,19 @@
*/
package org.alfresco.rest.workflow.api.impl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.activiti.engine.form.StartFormData;
import org.activiti.engine.impl.form.StartFormHandler;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.alfresco.repo.i18n.MessageService;
@@ -34,7 +40,11 @@ import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.repo.workflow.WorkflowObjectFactory;
import org.alfresco.repo.workflow.WorkflowQNameConverter;
import org.alfresco.rest.antlr.WhereClauseParser;
import org.alfresco.rest.framework.core.exceptions.ApiException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.content.FileBinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
@@ -44,6 +54,8 @@ import org.alfresco.rest.workflow.api.model.FormModelElement;
import org.alfresco.rest.workflow.api.model.ProcessDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.io.IOUtils;
public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessDefinitions
{
@@ -55,6 +67,9 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD
"category", "key", "name"
}));
private static final Set<String> PROCESS_DEFINITION_COLLECTION_SORT_PROPERTIES = new HashSet<String>(Arrays.asList(
"deploymentId", "key", "category", "id", "version", "name"
));
MessageService messageService;
String engineId;
@@ -79,52 +94,135 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD
ProcessDefinitionQuery query = activitiProcessEngine
.getRepositoryService()
.createProcessDefinitionQuery()
.processDefinitionCategoryNotEquals(WorkflowDeployer.CATEGORY_ALFRESCO_INTERNAL)
.orderByProcessDefinitionName().asc()
.orderByProcessDefinitionVersion().asc();
// Filter based on tenant, if required
if (tenantService.isEnabled() && deployWorkflowsInTenant)
{
query.processDefinitionKeyLike("@" + TenantUtil.getCurrentDomain() + "@%");
}
.processDefinitionCategoryNotEquals(WorkflowDeployer.CATEGORY_ALFRESCO_INTERNAL);
MapBasedQueryWalker propertyWalker = new MapBasedQueryWalker(PROCESS_DEFINITION_COLLECTION_EQUALS_QUERY_PROPERTIES,
PROCESS_DEFINITION_COLLECTION_MATCHES_QUERY_PROPERTIES);
boolean keyQueryIncluded = false;
if(parameters.getQuery() != null)
{
QueryHelper.walk(parameters.getQuery(), propertyWalker);
// Property equals
if(propertyWalker.getProperty("category", WhereClauseParser.EQUALS) != null) {
query.processDefinitionCategory(propertyWalker.getProperty("category", WhereClauseParser.EQUALS));
String categoryProperty = propertyWalker.getProperty("category", WhereClauseParser.EQUALS);
if (categoryProperty != null)
{
query.processDefinitionCategory(categoryProperty);
}
if(propertyWalker.getProperty("key", WhereClauseParser.EQUALS) != null) {
query.processDefinitionKey(propertyWalker.getProperty("key", WhereClauseParser.EQUALS));
String keyProperty = propertyWalker.getProperty("key", WhereClauseParser.EQUALS);
if (keyProperty != null)
{
query.processDefinitionKey(getProcessDefinitionKey(keyProperty));
keyQueryIncluded = true;
}
if(propertyWalker.getProperty("name", WhereClauseParser.EQUALS) != null) {
query.processDefinitionName(propertyWalker.getProperty("name", WhereClauseParser.EQUALS));
String nameProperty = propertyWalker.getProperty("name", WhereClauseParser.EQUALS);
if (nameProperty != null)
{
query.processDefinitionName(nameProperty);
}
if(propertyWalker.getProperty("version", WhereClauseParser.EQUALS) != null) {
query.processDefinitionVersion(propertyWalker.getProperty("version", WhereClauseParser.EQUALS, Integer.class));
Integer versionProperty = propertyWalker.getProperty("version", WhereClauseParser.EQUALS, Integer.class);
if (versionProperty != null)
{
query.processDefinitionVersion(versionProperty);
}
if(propertyWalker.getProperty("deploymentId", WhereClauseParser.EQUALS) != null) {
query.deploymentId(propertyWalker.getProperty("deploymentId", WhereClauseParser.EQUALS));
String deploymentProperty = propertyWalker.getProperty("deploymentId", WhereClauseParser.EQUALS);
if (deploymentProperty != null)
{
query.deploymentId(deploymentProperty);
}
// Property matches
if(propertyWalker.getProperty("category", WhereClauseParser.MATCHES) != null) {
query.processDefinitionCategoryLike(propertyWalker.getProperty("category", WhereClauseParser.MATCHES));
String categoryMatchesProperty = propertyWalker.getProperty("category", WhereClauseParser.MATCHES);
if (categoryMatchesProperty != null)
{
query.processDefinitionCategoryLike(categoryMatchesProperty);
}
if(propertyWalker.getProperty("key", WhereClauseParser.MATCHES) != null) {
query.processDefinitionKeyLike(propertyWalker.getProperty("key", WhereClauseParser.MATCHES));
String keyMatchesProperty = propertyWalker.getProperty("key", WhereClauseParser.MATCHES);
if (keyMatchesProperty != null)
{
query.processDefinitionKeyLike(getProcessDefinitionKey(keyMatchesProperty));
keyQueryIncluded = true;
}
if(propertyWalker.getProperty("name", WhereClauseParser.MATCHES) != null) {
query.processDefinitionNameLike(propertyWalker.getProperty("name", WhereClauseParser.MATCHES));
String nameLikeProperty = propertyWalker.getProperty("name", WhereClauseParser.MATCHES);
if (nameLikeProperty != null)
{
query.processDefinitionNameLike(nameLikeProperty);
}
}
// Filter based on tenant, if required
if (keyQueryIncluded == false && tenantService.isEnabled() && deployWorkflowsInTenant)
{
query.processDefinitionKeyLike("@" + TenantUtil.getCurrentDomain() + "@%");
}
String sortParam = parameters.getParameter("sort");
if (sortParam != null)
{
if (PROCESS_DEFINITION_COLLECTION_SORT_PROPERTIES.contains(sortParam))
{
if ("id".equalsIgnoreCase(sortParam))
{
query.orderByProcessDefinitionId();
}
else if ("deploymentId".equalsIgnoreCase(sortParam))
{
query.orderByDeploymentId();
}
else if ("key".equalsIgnoreCase(sortParam))
{
query.orderByProcessDefinitionKey();
}
else if ("category".equalsIgnoreCase(sortParam))
{
query.orderByProcessDefinitionCategory();
}
else if ("version".equalsIgnoreCase(sortParam))
{
query.orderByProcessDefinitionVersion();
}
else if ("name".equalsIgnoreCase(sortParam))
{
query.orderByProcessDefinitionName();
}
}
else
{
throw new InvalidArgumentException("sort " + sortParam +
" is not supported, supported items are " + PROCESS_DEFINITION_COLLECTION_SORT_PROPERTIES.toArray());
}
String sortOrderParam = parameters.getParameter("sortOrder");
if (sortOrderParam != null)
{
if ("asc".equalsIgnoreCase(sortOrderParam))
{
query.asc();
}
else if ("desc".equalsIgnoreCase(sortOrderParam))
{
query.desc();
}
else
{
throw new InvalidArgumentException("sort order " + sortOrderParam +
" is not supported, supported items are asc and desc");
}
}
}
else
{
query.orderByProcessDefinitionId().asc();
}
List<org.activiti.engine.repository.ProcessDefinition> processDefinitions =
query.listPage(parameters.getPaging().getSkipCount(), parameters.getPaging().getMaxItems());
@@ -160,10 +258,70 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD
ProcessDefinition deploymentRest = createProcessDefinitionRest((ProcessDefinitionEntity) processDefinition);
return deploymentRest;
}
@Override
public BinaryResource getProcessDefinitionImage(String definitionId)
{
ProcessDefinitionQuery query = activitiProcessEngine
.getRepositoryService()
.createProcessDefinitionQuery()
.processDefinitionId(definitionId);
if (tenantService.isEnabled() && deployWorkflowsInTenant)
{
query.processDefinitionKeyLike("@" + TenantUtil.getCurrentDomain() + "@%");
}
org.activiti.engine.repository.ProcessDefinition processDefinition = query.singleResult();
if (processDefinition == null)
{
throw new EntityNotFoundException(definitionId);
}
try
{
InputStream processDiagram = activitiProcessEngine.getRepositoryService().getProcessDiagram(definitionId);
if (processDiagram != null)
{
File file = TempFileProvider.createTempFile(definitionId + UUID.randomUUID(), ".png");
FileOutputStream fos = new FileOutputStream(file);
IOUtils.copy(processDiagram, fos);
fos.close();
return new FileBinaryResource(file);
}
else
{
throw new ApiException("No image available for definitionId " + definitionId);
}
}
catch (IOException error)
{
throw new ApiException("Error while getting process definition image.");
}
}
@Override
public CollectionWithPagingInfo<FormModelElement> getStartFormModel(String definitionId, Paging paging)
{
// first validate if user is allowed to access the process definition if workflows are deployed per tenant
if (tenantService.isEnabled() && deployWorkflowsInTenant)
{
ProcessDefinitionQuery query = activitiProcessEngine
.getRepositoryService()
.createProcessDefinitionQuery()
.processDefinitionId(definitionId);
query.processDefinitionKeyLike("@" + TenantUtil.getCurrentDomain() + "@%");
org.activiti.engine.repository.ProcessDefinition processDefinition = query.singleResult();
if (processDefinition == null)
{
throw new EntityNotFoundException(definitionId);
}
}
StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(definitionId);
if (startFormData == null)
{
@@ -183,23 +341,88 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD
TypeDefinition startTaskType = workflowFactory.getTaskFullTypeDefinition(startFormData.getFormKey(), true);
return getFormModelElements(startTaskType, paging);
}
protected String getProcessDefinitionKey(String key)
{
String processDefKey = null;
if (tenantService.isEnabled() && deployWorkflowsInTenant)
{
processDefKey = "@" + TenantUtil.getCurrentDomain() + "@" + key;
}
else
{
processDefKey = key;
}
return processDefKey;
}
protected String getLocalProcessDefinitionKey(String key)
{
String processDefKey = null;
if (tenantService.isEnabled() && deployWorkflowsInTenant)
{
processDefKey = key.substring(key.lastIndexOf("@") + 1);
}
else
{
processDefKey = key;
}
return processDefKey;
}
protected ProcessDefinition createProcessDefinitionRest(ProcessDefinitionEntity processDefinition)
{
ProcessDefinition processDefinitionRest = new ProcessDefinition(processDefinition);
String localKey = getLocalProcessDefinitionKey(processDefinition.getKey());
processDefinitionRest.setKey(localKey);
String displayId = localKey + ".workflow";
processDefinitionRest.setTitle(getLabel(displayId, "title"));
processDefinitionRest.setDescription(getLabel(displayId, "description"));
processDefinitionRest.setGraphicNotationDefined(processDefinition.isGraphicalNotationDefined());
if (processDefinition.hasStartFormKey())
{
try {
StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(processDefinition.getId());
try
{
StartFormData startFormData = null;
ProcessDefinitionEntity definitionEntity = getCachedProcessDefinition(processDefinition.getId());
if (definitionEntity != null)
{
StartFormHandler startFormHandler = definitionEntity.getStartFormHandler();
if (startFormHandler == null) {
throw new ApiException("No start form defined for " + processDefinition.getId());
}
startFormData = startFormHandler.createStartFormData(definitionEntity);
}
else
{
startFormData = activitiProcessEngine.getFormService().getStartFormData(processDefinition.getId());
}
if (startFormData != null)
{
processDefinitionRest.setStartFormResourceKey(startFormData.getFormKey());
}
} catch(Exception e) {
e.printStackTrace();
}
catch (ApiException e)
{
throw e;
}
catch (Exception e)
{
throw new ApiException("Error while retrieving start form key");
}
}
return processDefinitionRest;
}
protected String getLabel(String displayId, String labelKey)
{
String keyBase = displayId.replace(":", "_");
String key = keyBase+ "." + labelKey;
String label = messageService.getMessage(key);
return label;
}
}

View File

@@ -39,13 +39,11 @@ import org.activiti.engine.RuntimeService;
import org.activiti.engine.form.StartFormData;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.i18n.MessageService;
@@ -71,7 +69,6 @@ import org.alfresco.rest.antlr.WhereClauseParser;
import org.alfresco.rest.framework.core.exceptions.ApiException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.content.FileBinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
@@ -90,12 +87,15 @@ import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.InvalidQNameException;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ISO8601DateFormat;
import org.alfresco.util.TempFileProvider;
import org.alfresco.util.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
@@ -142,6 +142,10 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
"startedAt", "endedAt"
));
private static final Set<String> PROCESS_COLLECTION_SORT_PROPERTIES = new HashSet<String>(Arrays.asList(
"processDefinitionId", "businessKey", "id", "startedAt", "endedAt", "durationInMillis"
));
public void setAuthorityDAO(AuthorityDAO authorityDAO)
{
this.authorityDAO = authorityDAO;
@@ -303,8 +307,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
final HistoricProcessInstanceQuery query = activitiProcessEngine
.getHistoryService()
.createHistoricProcessInstanceQuery()
.orderByProcessInstanceStartTime().desc();
.createHistoricProcessInstanceQuery();
if (processDefinitionId != null) query.processDefinitionId(processDefinitionId);
if (businessKey != null) query.processInstanceBusinessKey(businessKey);
@@ -400,12 +403,71 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
query.involvedUser(AuthenticationUtil.getRunAsUser());
}
String sortParam = parameters.getParameter("sort");
if (sortParam != null)
{
if (PROCESS_COLLECTION_SORT_PROPERTIES.contains(sortParam))
{
if ("processDefinitionId".equalsIgnoreCase(sortParam))
{
query.orderByProcessDefinitionId();
}
else if ("id".equalsIgnoreCase(sortParam))
{
query.orderByProcessInstanceId();
}
else if ("businessKey".equalsIgnoreCase(sortParam))
{
query.orderByProcessInstanceBusinessKey();
}
else if ("startedAt".equalsIgnoreCase(sortParam))
{
query.orderByProcessInstanceStartTime();
}
else if ("endedAt".equalsIgnoreCase(sortParam))
{
query.orderByProcessInstanceEndTime();
}
else if ("durationInMillis".equalsIgnoreCase(sortParam))
{
query.orderByProcessInstanceDuration();
}
}
else
{
throw new InvalidArgumentException("sort " + sortParam +
" is not supported, supported items are " + PROCESS_COLLECTION_SORT_PROPERTIES.toArray());
}
String sortOrderParam = parameters.getParameter("sortOrder");
if (sortOrderParam != null)
{
if ("asc".equalsIgnoreCase(sortOrderParam))
{
query.asc();
}
else if ("desc".equalsIgnoreCase(sortOrderParam))
{
query.desc();
}
else
{
throw new InvalidArgumentException("sort order " + sortOrderParam +
" is not supported, supported items are asc and desc");
}
}
}
else
{
query.orderByProcessInstanceStartTime().desc();
}
List<HistoricProcessInstance> processInstances = query.listPage(paging.getSkipCount(), paging.getMaxItems());
List<ProcessInfo> page = new ArrayList<ProcessInfo>(processInstances.size());
for (HistoricProcessInstance processInstance: processInstances)
{
page.add(new ProcessInfo(processInstance));
page.add(createProcessInfo(processInstance));
}
return CollectionWithPagingInfo.asPaged(paging, page, false, page.size());
@@ -419,8 +481,6 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new InvalidArgumentException("processId is required to get the process info");
}
validateIfUserAllowedToWorkWithProcess(processId);
HistoricProcessInstance processInstance = activitiProcessEngine
.getHistoryService()
.createHistoricProcessInstanceQuery()
@@ -429,10 +489,10 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
if (processInstance == null)
{
throw new EntityNotFoundException("could not find process for id " + processId);
throw new EntityNotFoundException(processId);
}
return new ProcessInfo(processInstance);
return createProcessInfo(processInstance);
}
@Override
@@ -455,7 +515,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
ProcessDefinition definition = activitiProcessEngine
.getRepositoryService()
.createProcessDefinitionQuery()
.processDefinitionKey(createProcessDefinitionKey(process.getProcessDefinitionKey()))
.processDefinitionKey(getProcessDefinitionKey(process.getProcessDefinitionKey()))
.latestVersion()
.singleResult();
@@ -475,7 +535,17 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
if(!definitionExistingChecked)
{
// Check if the required definition actually exists
if(activitiProcessEngine.getRepositoryService().createProcessDefinitionQuery().processDefinitionId(processDefinitionId).count() == 0)
ProcessDefinitionQuery query = activitiProcessEngine
.getRepositoryService()
.createProcessDefinitionQuery()
.processDefinitionId(processDefinitionId);
if (tenantService.isEnabled() && deployWorkflowsInTenant)
{
query.processDefinitionKeyLike("@" + TenantUtil.getCurrentDomain() + "@%");
}
if(query.count() == 0)
{
throw new InvalidArgumentException("No workflow definition could be found with id '" + processDefinitionId +"'.");
}
@@ -512,10 +582,14 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
if (taskAssociations.containsKey(propNameMap.get(variableName)))
{
AssociationDefinition associationDef = taskAssociations.get(propNameMap.get(variableName));
if (variableValue != null && "person".equalsIgnoreCase(associationDef.getTargetClass().getTitle(dictionaryService)))
if (variableValue != null && ContentModel.TYPE_PERSON.equals(associationDef.getTargetClass().getName()))
{
variableValue = getPersonNodeRef(variableValue.toString());
}
else if (variableValue != null && ContentModel.TYPE_AUTHORITY_CONTAINER.equals(associationDef.getTargetClass().getName()))
{
variableValue = authorityService.getAuthorityNodeRef(variableValue.toString());
}
}
if (variableValue instanceof Serializable)
@@ -533,28 +607,29 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
NodeRef workflowPackageNodeRef = null;
try
{
workflowPackageNodeRef = workflowPackageComponent.createPackage(null);
startParams.put(WorkflowModel.ASSOC_PACKAGE, workflowPackageNodeRef);
workflowPackageNodeRef = workflowPackageComponent.createPackage(null);
startParams.put(WorkflowModel.ASSOC_PACKAGE, workflowPackageNodeRef);
}
catch (Exception e)
{
throw new ApiException("couldn't create workflow package: " + e.getMessage(), e);
throw new ApiException("couldn't create workflow package: " + e.getMessage(), e);
}
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(process.getItems()))
{
try
{
for (String item: process.getItems())
try
{
QName workflowPackageItemId = QName.createQName("wpi", item);
nodeService.addChild(workflowPackageNodeRef, new NodeRef(item), WorkflowModel.ASSOC_PACKAGE_CONTAINS, workflowPackageItemId);
for (String item: process.getItems())
{
NodeRef itemNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, item);
QName workflowPackageItemId = QName.createQName("wpi", itemNodeRef.toString());
nodeService.addChild(workflowPackageNodeRef, itemNodeRef, WorkflowModel.ASSOC_PACKAGE_CONTAINS, workflowPackageItemId);
}
}
catch (Exception e)
{
throw new ApiException("Error while adding items to package: " + e.getMessage(), e);
}
}
catch (Exception e)
{
throw new ApiException("Error while adding items to package: " + e.getMessage(), e);
}
}
// Set start task properties. This should be done before instance is started, since it's id will be used
@@ -578,7 +653,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
}
}
if(tenantService.isEnabled())
if (tenantService.isEnabled())
{
// Specify which tenant domain the workflow was started in.
variables.put(ActivitiConstants.VAR_TENANT_DOMAIN, TenantUtil.getCurrentDomain());
@@ -598,7 +673,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
.processInstanceId(processInstance.getId())
.singleResult();
return new ProcessInfo(historicProcessInstance);
return createProcessInfo(historicProcessInstance);
}
@Override
@@ -673,7 +748,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
List<ChildAssociationRef> documentList = nodeService.getChildAssocs(packageScriptNode.getNodeRef());
for (ChildAssociationRef childAssociationRef : documentList)
{
if (childAssociationRef.getChildRef().toString().equals(itemId))
if (childAssociationRef.getChildRef().getId().equals(itemId))
{
item = createItemForNodeRef(childAssociationRef.getChildRef());
break;
@@ -718,10 +793,22 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new InvalidArgumentException("process doesn't contain a workflow package variable");
}
// check if noderef exists
try
{
QName workflowPackageItemId = QName.createQName("wpi", item.getId());
nodeService.addChild(packageScriptNode.getNodeRef(), new NodeRef(item.getId()), WorkflowModel.ASSOC_PACKAGE_CONTAINS, workflowPackageItemId);
nodeService.getProperties(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, item.getId()));
}
catch (Exception e)
{
throw new EntityNotFoundException("item with id " + item.getId() + " not found");
}
try
{
NodeRef itemNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, item.getId());
QName workflowPackageItemId = QName.createQName("wpi", itemNodeRef.toString());
nodeService.addChild(packageScriptNode.getNodeRef(), itemNodeRef,
WorkflowModel.ASSOC_PACKAGE_CONTAINS, workflowPackageItemId);
}
catch (Exception e)
{
@@ -761,13 +848,29 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new InvalidArgumentException("process doesn't contain a workflow package variable");
}
boolean itemIdFoundInPackage = false;
List<ChildAssociationRef> documentList = nodeService.getChildAssocs(packageScriptNode.getNodeRef());
for (ChildAssociationRef childAssociationRef : documentList)
{
if (childAssociationRef.getChildRef().getId().equals(itemId))
{
itemIdFoundInPackage = true;
break;
}
}
if (itemIdFoundInPackage == false)
{
throw new EntityNotFoundException("Item " + itemId + " not found in the process package variable");
}
try
{
nodeService.removeChild(packageScriptNode.getNodeRef(), new NodeRef(itemId));
nodeService.removeChild(packageScriptNode.getNodeRef(), new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, itemId));
}
catch (Exception e)
catch (InvalidNodeRefException e)
{
throw new ApiException("could not delete item from process " + e.getMessage(), e);
throw new EntityNotFoundException("Item " + itemId + " not found");
}
}
@@ -822,6 +925,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
{
formKey = startFormData.getFormKey();
}
TypeDefinition startTaskTypeDefinition = workflowFactory.getTaskFullTypeDefinition(formKey, true);
// Convert raw variables to Variable objects
@@ -838,12 +942,41 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
ProcessInstance processInstance = activitiProcessEngine.getRuntimeService().createProcessInstanceQuery()
.processInstanceId(processId).singleResult();
if(processInstance == null)
if (processInstance == null)
{
throw new EntityNotFoundException(processId);
}
if(variable.getName() == null)
return updateVariableInProcess(processId, variable);
}
@Override
public List<Variable> updateVariables(String processId, List<Variable> variables)
{
validateIfUserAllowedToWorkWithProcess(processId);
ProcessInstance processInstance = activitiProcessEngine.getRuntimeService().createProcessInstanceQuery()
.processInstanceId(processId).singleResult();
if (processInstance == null)
{
throw new EntityNotFoundException(processId);
}
List<Variable> updatedVariables = new ArrayList<Variable>();
if (variables != null)
{
for (Variable variable : variables)
{
updatedVariables.add(updateVariableInProcess(processId, variable));
}
}
return updatedVariables;
}
protected Variable updateVariableInProcess(String processId,Variable variable)
{
if (variable.getName() == null)
{
throw new InvalidArgumentException("Variable name is required.");
}
@@ -872,9 +1005,18 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new InvalidArgumentException("Unsupported type of variable: '" + variable.getType() +"'.");
}
Object actualValue = null;
if ("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((String) variable.getValue());
}
else
{
actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, variable.getValue());
}
variable.setValue(actualValue);
// Get raw variable value and set value
Object actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, variable.getValue());
activitiProcessEngine.getRuntimeService().setVariable(processId, variable.getName(), actualValue);
// Set actual used type before returning
@@ -921,13 +1063,10 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
try
{
ProcessDefinition procDef = activitiProcessEngine.getRepositoryService().createProcessDefinitionQuery()
.processDefinitionId(processInstance.getProcessDefinitionId())
.singleResult();
BpmnModel model = activitiProcessEngine.getRepositoryService().getBpmnModel(processInstance.getProcessDefinitionId());
if(((ProcessDefinitionEntity) procDef).isGraphicalNotationDefined())
if(model != null && model.getLocationMap().size() > 0)
{
BpmnModel model = activitiProcessEngine.getRepositoryService().getBpmnModel(processInstance.getProcessDefinitionId());
List<String> activeActivities = activitiProcessEngine.getRuntimeService().getActiveActivityIds(processId);
InputStream generateDiagram = ProcessDiagramGenerator.generateDiagram(model, "png", activeActivities);
@@ -949,65 +1088,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
}
}
protected void validateIfUserAllowedToWorkWithProcess(String processId)
{
if (tenantService.isEnabled())
{
try
{
String tenantDomain = (String) activitiProcessEngine.getRuntimeService().getVariable(processId, ActivitiConstants.VAR_TENANT_DOMAIN);
if (TenantUtil.getCurrentDomain().equals(tenantDomain) == false)
{
throw new PermissionDeniedException("Process is running in another tenant");
}
}
catch (ActivitiObjectNotFoundException e)
{
throw new EntityNotFoundException(processId);
}
}
try
{
ActivitiScriptNode initiator = (ActivitiScriptNode) activitiProcessEngine.getRuntimeService().getVariable(processId, WorkflowConstants.PROP_INITIATOR);
if (AuthenticationUtil.getRunAsUser().equals(initiator.getNodeRef().getId()))
{
// user is allowed
return;
}
}
catch (ActivitiObjectNotFoundException e)
{
throw new EntityNotFoundException(processId);
}
HistoricTaskInstanceQuery query = activitiProcessEngine.getHistoryService()
.createHistoricTaskInstanceQuery()
.processInstanceId(processId);
if (authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser()))
{
// Admin is allowed to read all processes in the current tenant
if (tenantService.isEnabled())
{
query.processVariableValueEquals(ActivitiConstants.VAR_TENANT_DOMAIN, TenantUtil.getCurrentDomain());
}
}
else
{
// If non-admin user, involvement in the task is required (either owner, assignee or externally involved).
query.taskInvolvedUser(AuthenticationUtil.getRunAsUser());
}
List<HistoricTaskInstance> taskList = query.list();
if(org.apache.commons.collections.CollectionUtils.isEmpty(taskList))
{
throw new PermissionDeniedException("user is not allowed to access information about process " + processId);
}
}
protected String createProcessDefinitionKey(String paramProcessDefinitionKey)
protected String getProcessDefinitionKey(String paramProcessDefinitionKey)
{
String processDefinitionKey = null;
if (tenantService.isEnabled() && deployWorkflowsInTenant)
@@ -1020,6 +1101,20 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
}
return processDefinitionKey;
}
protected String getLocalProcessDefinitionKey(String key)
{
String processDefKey = null;
if (tenantService.isEnabled() && deployWorkflowsInTenant)
{
processDefKey = key.substring(key.lastIndexOf("@") + 1);
}
else
{
processDefKey = key;
}
return processDefKey;
}
protected NodeRef getPersonNodeRef(String name)
{
@@ -1034,6 +1129,18 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
return authority;
}
protected ProcessInfo createProcessInfo(HistoricProcessInstance processInstance)
{
ProcessInfo processInfo = new ProcessInfo(processInstance);
ProcessDefinition definitionEntity = getCachedProcessDefinition(processInstance.getProcessDefinitionId());
if (definitionEntity == null)
{
definitionEntity = activitiProcessEngine.getRepositoryService().getProcessDefinition(processInstance.getProcessDefinitionId());
}
processInfo.setProcessDefinitionKey(getLocalProcessDefinitionKey(definitionEntity.getKey()));
return processInfo;
}
protected Item createItemForNodeRef(NodeRef nodeRef) {
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
Item item = new Item();
@@ -1047,7 +1154,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
item.setId(nodeRef.toString());
item.setId(nodeRef.getId());
item.setName(name);
item.setTitle(title);
item.setDescription(description);

View File

@@ -30,6 +30,8 @@ import org.activiti.engine.ActivitiTaskAlreadyClaimedException;
import org.activiti.engine.form.FormData;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.IdentityLinkType;
import org.activiti.engine.task.TaskQuery;
@@ -57,6 +59,7 @@ import org.alfresco.rest.workflow.api.model.FormModelElement;
import org.alfresco.rest.workflow.api.model.Item;
import org.alfresco.rest.workflow.api.model.Task;
import org.alfresco.rest.workflow.api.model.TaskCandidate;
import org.alfresco.rest.workflow.api.model.TaskStateTransition;
import org.alfresco.rest.workflow.api.model.TaskVariable;
import org.alfresco.rest.workflow.api.model.VariableScope;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
@@ -64,8 +67,10 @@ 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.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.namespace.InvalidQNameException;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ISO8601DateFormat;
public class TasksImpl extends WorkflowRestImpl implements Tasks
{
@@ -76,12 +81,12 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
* All properties that are read-only and cannot be updated on a single task-resource.
*/
private static final List<String> TASK_READ_ONLY_PROPERTIES = Arrays.asList(
"id", "processId", "processDefinitionId", "actibityDefinitionId", "startedAt", "endedAt", "durationInMs", "formResourceKey"
"id", "processId", "processDefinitionId", "activityDefinitionId", "startedAt", "endedAt", "durationInMs", "formResourceKey"
);
private static final Set<String> TASK_COLLECTION_EQUALS_QUERY_PROPERTIES = new HashSet<String>(Arrays.asList(
"status", "assignee", "owner", "candidateUser", "candidateGroup", "name", "description", "priority", "processInstanceId",
"processInstanceBusinessKey", "activityDefinitionId", "processDefinitionId", "processDefinitionName", "startedAt", "dueAt"
"status", "assignee", "owner", "candidateUser", "candidateGroup", "name", "description", "priority", "processId",
"processBusinessKey", "activityDefinitionId", "processDefinitionId", "processDefinitionName", "startedAt", "dueAt"
));
private static final Set<String> TASK_COLLECTION_MATCHES_QUERY_PROPERTIES = new HashSet<String>(Arrays.asList(
@@ -104,6 +109,14 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
"priority"
));
private static final Set<String> TASK_COLLECTION_RUNNING_SORT_PROPERTIES = new HashSet<String>(Arrays.asList(
"id", "name", "description", "priority", "processId", "assignee", "startedAt", "dueAt"
));
private static final Set<String> TASK_COLLECTION_HISTORY_SORT_PROPERTIES = new HashSet<String>(Arrays.asList(
"id", "name", "description", "priority", "processId", "processDefinitionId", "assignee", "owner", "startedAt", "endedAt", "durationInMs", "dueAt"
));
private RestVariableHelper restVariableHelper;
private WorkflowObjectFactory workflowFactory;
private WorkflowQNameConverter qNameConverter;
@@ -155,8 +168,8 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
Integer priority = propertyWalker.getProperty("priority", WhereClauseParser.EQUALS, Integer.class);
Integer priorityGreaterThanOrEquals = propertyWalker.getProperty("priority", WhereClauseParser.GREATERTHANOREQUALS, Integer.class);
Integer priorityLessThanOrEquals = propertyWalker.getProperty("priority", WhereClauseParser.LESSTHANOREQUALS, Integer.class);
String processInstanceId = propertyWalker.getProperty("processInstanceId", WhereClauseParser.EQUALS);
String processInstanceBusinessKey = propertyWalker.getProperty("processInstanceBusinessKey", WhereClauseParser.EQUALS);
String processInstanceId = propertyWalker.getProperty("processId", WhereClauseParser.EQUALS);
String processInstanceBusinessKey = propertyWalker.getProperty("processBusinessKey", WhereClauseParser.EQUALS);
String activityDefinitionId = propertyWalker.getProperty("activityDefinitionId", WhereClauseParser.EQUALS);
String activityDefinitionIdLike = propertyWalker.getProperty("activityDefinitionId", WhereClauseParser.MATCHES);
String processDefinitionId = propertyWalker.getProperty("processDefinitionId", WhereClauseParser.EQUALS);
@@ -177,7 +190,30 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
if (assignee != null) query.taskAssignee(assignee);
if (owner != null) query.taskOwner(owner);
if (candidateUser != null) query.taskCandidateUser(candidateUser);
if (candidateUser != null)
{
Set<String> parents = authorityService.getContainingAuthorities(AuthorityType.GROUP, candidateUser, false);
if (parents != null)
{
List<String> authorities = new ArrayList<String>();
authorities.addAll(parents);
// there's a limitation in at least Oracle for using an IN statement with more than 1000 items
if (parents.size() > 1000)
{
authorities = authorities.subList(0, 1000);
}
if (authorities.size() > 0)
{
query.taskCandidateGroupIn(authorities);
}
else
{
query.taskCandidateUser(candidateUser);
}
}
}
if (candidateGroup != null) query.taskCandidateGroup(candidateGroup);
if (name != null) query.taskName(name);
if (nameLike != null) query.taskNameLike(nameLike);
@@ -208,6 +244,30 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
{
query.taskVariableValueEquals(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.GREATERTHAN)
{
query.taskVariableValueGreaterThan(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.GREATERTHANOREQUALS)
{
query.taskVariableValueGreaterThanOrEqual(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.LESSTHAN)
{
query.taskVariableValueLessThan(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.LESSTHANOREQUALS)
{
query.taskVariableValueLessThanOrEqual(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.MATCHES)
{
if (queryVariableHolder.getPropertyValue() instanceof String == false)
{
throw new InvalidArgumentException("the matches operator can only be used with a String value for property " + queryVariableHolder.getPropertyName());
}
query.taskVariableValueLike(queryVariableHolder.getPropertyName(), (String) queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.NEGATION)
{
query.taskVariableValueNotEquals(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
@@ -285,6 +345,30 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
{
query.taskVariableValueEquals(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.GREATERTHAN)
{
query.taskVariableValueGreaterThan(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.GREATERTHANOREQUALS)
{
query.taskVariableValueGreaterThanOrEqual(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.LESSTHAN)
{
query.taskVariableValueLessThan(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.LESSTHANOREQUALS)
{
query.taskVariableValueLessThanOrEqual(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.MATCHES)
{
if (queryVariableHolder.getPropertyValue() instanceof String == false)
{
throw new InvalidArgumentException("the matches operator can only be used with a String value for property " + queryVariableHolder.getPropertyName());
}
query.taskVariableValueLike(queryVariableHolder.getPropertyName(), (String) queryVariableHolder.getPropertyValue());
}
else if (queryVariableHolder.getOperator() == WhereClauseParser.NEGATION)
{
query.taskVariableValueNotEquals(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
@@ -325,6 +409,220 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
return CollectionWithPagingInfo.asPaged(paging, page, false, page.size());
}
@Override
public CollectionWithPagingInfo<Task> getTasks(String processId, Parameters parameters)
{
Paging paging = parameters.getPaging();
String status = parameters.getParameter("status");
validateIfUserAllowedToWorkWithProcess(processId);
List<Task> page = null;
if (status == null || STATUS_ACTIVE.equals(status))
{
TaskQuery query = activitiProcessEngine
.getTaskService()
.createTaskQuery();
query.processInstanceId(processId);
String sortParam = parameters.getParameter("sort");
if (sortParam != null)
{
if (TASK_COLLECTION_RUNNING_SORT_PROPERTIES.contains(sortParam))
{
if ("id".equalsIgnoreCase(sortParam))
{
query.orderByTaskId();
}
else if ("name".equalsIgnoreCase(sortParam))
{
query.orderByTaskName();
}
else if ("description".equalsIgnoreCase(sortParam))
{
query.orderByTaskDescription();
}
else if ("priority".equalsIgnoreCase(sortParam))
{
query.orderByTaskPriority();
}
else if ("processId".equalsIgnoreCase(sortParam))
{
query.orderByProcessInstanceId();
}
else if ("assignee".equalsIgnoreCase(sortParam))
{
query.orderByTaskAssignee();
}
else if ("startedAt".equalsIgnoreCase(sortParam))
{
query.orderByTaskCreateTime();
}
else if ("dueAt".equalsIgnoreCase(sortParam))
{
query.orderByDueDate();
}
}
else
{
throw new InvalidArgumentException("sort " + sortParam +
" is not supported, supported items are " + TASK_COLLECTION_RUNNING_SORT_PROPERTIES.toArray());
}
String sortOrderParam = parameters.getParameter("sortOrder");
if (sortOrderParam != null)
{
if ("asc".equalsIgnoreCase(sortOrderParam))
{
query.asc();
}
else if ("desc".equalsIgnoreCase(sortOrderParam))
{
query.desc();
}
else
{
throw new InvalidArgumentException("sort order " + sortOrderParam +
" is not supported, supported items are asc and desc");
}
}
}
else
{
query.orderByDueDate().asc();
}
List<org.activiti.engine.task.Task> tasks = query.listPage(paging.getSkipCount(), paging.getMaxItems());
page = new ArrayList<Task>(tasks.size());
for (org.activiti.engine.task.Task taskInstance: tasks)
{
Task task = new Task(taskInstance);
task.setFormResourceKey(getFormResourceKey(taskInstance));
page.add(task);
}
}
else if (STATUS_COMPLETED.equals(status) || STATUS_ANY.equals(status))
{
HistoricTaskInstanceQuery query = activitiProcessEngine
.getHistoryService()
.createHistoricTaskInstanceQuery();
if (STATUS_COMPLETED.equals(status)) query.finished();
query.processInstanceId(processId);
// Add tenant filtering
if(tenantService.isEnabled()) {
query.processVariableValueEquals(ActivitiConstants.VAR_TENANT_DOMAIN, TenantUtil.getCurrentDomain());
}
// Add involvment filtering if user is not admin
if(!authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser())) {
query.taskInvolvedUser(AuthenticationUtil.getRunAsUser());
}
String sortParam = parameters.getParameter("sort");
if (sortParam != null)
{
if (TASK_COLLECTION_HISTORY_SORT_PROPERTIES.contains(sortParam))
{
if ("id".equalsIgnoreCase(sortParam))
{
query.orderByTaskId();
}
else if ("name".equalsIgnoreCase(sortParam))
{
query.orderByTaskName();
}
else if ("description".equalsIgnoreCase(sortParam))
{
query.orderByTaskDescription();
}
else if ("priority".equalsIgnoreCase(sortParam))
{
query.orderByTaskPriority();
}
else if ("processId".equalsIgnoreCase(sortParam))
{
query.orderByProcessInstanceId();
}
else if ("processDefinitionId".equalsIgnoreCase(sortParam))
{
query.orderByProcessDefinitionId();
}
else if ("assignee".equalsIgnoreCase(sortParam))
{
query.orderByTaskAssignee();
}
else if ("owner".equalsIgnoreCase(sortParam))
{
query.orderByTaskOwner();
}
else if ("startedAt".equalsIgnoreCase(sortParam))
{
query.orderByHistoricTaskInstanceStartTime();
}
else if ("endedAt".equalsIgnoreCase(sortParam))
{
query.orderByHistoricTaskInstanceEndTime();
}
else if ("durationInMs".equalsIgnoreCase(sortParam))
{
query.orderByHistoricTaskInstanceDuration();
}
else if ("dueAt".equalsIgnoreCase(sortParam))
{
query.orderByTaskDueDate();
}
}
else
{
throw new InvalidArgumentException("sort " + sortParam +
" is not supported, supported items are " + TASK_COLLECTION_HISTORY_SORT_PROPERTIES.toArray());
}
String sortOrderParam = parameters.getParameter("sortOrder");
if (sortOrderParam != null)
{
if ("asc".equalsIgnoreCase(sortOrderParam))
{
query.asc();
}
else if ("desc".equalsIgnoreCase(sortOrderParam))
{
query.desc();
}
else
{
throw new InvalidArgumentException("sort order " + sortOrderParam +
" is not supported, supported items are asc and desc");
}
}
}
else
{
query.orderByTaskDueDate().asc();
}
List<HistoricTaskInstance> tasks = query.listPage(paging.getSkipCount(), paging.getMaxItems());
page = new ArrayList<Task>(tasks.size());
for (HistoricTaskInstance taskInstance: tasks)
{
Task task = new Task(taskInstance);
page.add(task);
}
}
else
{
throw new InvalidArgumentException("Invalid status parameter: " + status);
}
return CollectionWithPagingInfo.asPaged(paging, page, false, page.size());
}
@Override
public Task getTask(String taskId)
@@ -509,7 +807,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
}
// Lookup type definition for the task
TypeDefinition taskType = workflowFactory.getTaskFullTypeDefinition(formData.getFormKey(), true);
TypeDefinition taskType = getWorkflowFactory().getTaskFullTypeDefinition(formData.getFormKey(), true);
return getFormModelElements(taskType, paging);
}
@@ -543,7 +841,25 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
public TaskVariable updateTaskVariable(String taskId, TaskVariable taskVariable)
{
org.activiti.engine.task.Task taskInstance = getValidTask(taskId, true);
return updateVariableInTask(taskId, taskInstance, taskVariable);
}
public List<TaskVariable> updateTaskVariables(String taskId, List<TaskVariable> variables)
{
org.activiti.engine.task.Task taskInstance = getValidTask(taskId, true);
List<TaskVariable> updatedVariables = new ArrayList<TaskVariable>();
if (variables != null)
{
for (TaskVariable variable : variables)
{
updatedVariables.add(updateVariableInTask(taskId, taskInstance, variable));
}
}
return updatedVariables;
}
protected TaskVariable updateVariableInTask(String taskId, org.activiti.engine.task.Task taskInstance, TaskVariable taskVariable)
{
if(taskVariable.getName() == null)
{
throw new InvalidArgumentException("Variable name is required.");
@@ -603,12 +919,22 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
}
}
if(dataTypeDefinition == null)
if (dataTypeDefinition == null)
{
throw new InvalidArgumentException("Unsupported type of variable: '" + taskVariable.getType() +"'.");
}
Object actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, taskVariable.getValue());
Object actualValue = null;
if ("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((String) taskVariable.getValue());
}
else
{
actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, taskVariable.getValue());
}
taskVariable.setValue(actualValue);
if (VariableScope.LOCAL.equals(taskVariable.getVariableScope()))
{
@@ -716,10 +1042,27 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
return processes.getItems(task.getProcessInstanceId(), paging);
}
protected String getFormResourceKey(org.activiti.engine.task.Task task) {
protected String getFormResourceKey(final org.activiti.engine.task.Task task)
{
if (task.getProcessDefinitionId() != null)
{
return activitiProcessEngine.getFormService().getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
ProcessDefinitionEntity definitionEntity = getCachedProcessDefinition(task.getProcessDefinitionId());
String formKey = null;
if (definitionEntity != null)
{
TaskDefinition taskDefinition = definitionEntity.getTaskDefinitions().get(task.getTaskDefinitionKey());
if (taskDefinition != null)
{
formKey = taskDefinition.getTaskFormHandler().getFormKey().getExpressionText();
}
}
else
{
formKey = activitiProcessEngine.getFormService().getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
}
return formKey;
}
else
{
@@ -910,10 +1253,10 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
// Task is not yet finished, so potentially claimable. If user is part of a "candidateGroup", the task is accessible to the
// user regardless of not being involved/owner/assignee
isTaskClaimable = activitiProcessEngine.getTaskService()
.createTaskQuery()
.taskCandidateGroupIn(new ArrayList<String>(authorityService.getAuthoritiesForUser(AuthenticationUtil.getRunAsUser())))
.taskId(taskId)
.count() == 1;
.createTaskQuery()
.taskCandidateGroupIn(new ArrayList<String>(authorityService.getAuthoritiesForUser(AuthenticationUtil.getRunAsUser())))
.taskId(taskId)
.count() == 1;
}
if(!isTaskClaimable)
@@ -943,26 +1286,4 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
}
return workflowFactory;
}
private enum TaskStateTransition {
COMPLETED, CLAIMED, UNCLAIMED, DELEGATED, RESOLVED;
/**
* @return the {@link TaskStateTransition} for the given string
* @throws InvalidArgumentException when no action exists for the given string
*/
public static TaskStateTransition getTaskActionFromString(String action)
{
for(TaskStateTransition taskAction : values())
{
if(taskAction.name().toLowerCase().equals(action))
{
return taskAction;
}
}
throw new InvalidArgumentException("The task state property has an invalid value: " + action);
}
}
}

View File

@@ -1,6 +1,7 @@
package org.alfresco.rest.workflow.api.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
@@ -9,16 +10,36 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.activiti.engine.ActivitiObjectNotFoundException;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.ProcessEngineImpl;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.deploy.DeploymentCache;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.workflow.WorkflowConstants;
import org.alfresco.repo.workflow.activiti.ActivitiConstants;
import org.alfresco.repo.workflow.activiti.ActivitiScriptNode;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.workflow.api.model.FormModelElement;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.Constraint;
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
@@ -42,6 +63,7 @@ public class WorkflowRestImpl
protected DictionaryService dictionaryService;
protected ProcessEngine activitiProcessEngine;
protected boolean deployWorkflowsInTenant;
protected List<String> excludeModelTypes = new ArrayList<String>(Arrays.asList("bpm_priority", "bpm_description", "bpm_dueDate"));
static
{
@@ -81,6 +103,32 @@ public class WorkflowRestImpl
this.deployWorkflowsInTenant = deployWorkflowsInTenant;
}
/**
* Get the process definition from the cache if available
*
* @param processDefinitionId the unique id identifier of the process definition
*/
public ProcessDefinitionEntity getCachedProcessDefinition(final String processDefinitionId)
{
ProcessEngineConfigurationImpl processConfig = (ProcessEngineConfigurationImpl) ((ProcessEngineImpl) activitiProcessEngine).getProcessEngineConfiguration();
ProcessDefinitionEntity definitionEntity = processConfig.getCommandExecutorTxRequired().execute(new Command<ProcessDefinitionEntity>()
{
@Override
public ProcessDefinitionEntity execute(CommandContext commandContext)
{
DeploymentCache<ProcessDefinitionEntity> cache = Context
.getProcessEngineConfiguration()
.getDeploymentManager()
.getProcessDefinitionCache();
return cache.get(processDefinitionId);
}
});
return definitionEntity;
}
/**
* Get the first parameter value, converted to the requested type.
* @param parameters used to extract parameter value from
@@ -131,16 +179,33 @@ public class WorkflowRestImpl
List<FormModelElement> page = new ArrayList<FormModelElement>();
for (Entry<QName, PropertyDefinition> entry : taskProperties.entrySet())
{
String name = entry.getKey().toPrefixString(namespaceService).replace(':', '_');
// Only add properties which are not part of an excluded type
if(!typesToExclude.contains(entry.getValue().getContainerClass().getName()))
if(!typesToExclude.contains(entry.getValue().getContainerClass().getName()) && excludeModelTypes.contains(name) == false)
{
FormModelElement element = new FormModelElement();
element.setName(entry.getKey().toPrefixString(namespaceService).replace(':', '_'));
element.setName(name);
element.setQualifiedName(entry.getKey().toString());
element.setTitle(entry.getValue().getTitle(dictionaryService));
element.setRequired(entry.getValue().isMandatory());
element.setDataType(entry.getValue().getDataType().getName().toPrefixString(namespaceService));
element.setDefaultValue(entry.getValue().getDefaultValue());
if (entry.getValue().getConstraints() != null)
{
for (ConstraintDefinition constraintDef : entry.getValue().getConstraints())
{
Constraint constraint = constraintDef.getConstraint();
if (constraint != null && constraint instanceof ListOfValuesConstraint)
{
ListOfValuesConstraint valuesConstraint = (ListOfValuesConstraint) constraint;
if (valuesConstraint.getAllowedValues() != null && valuesConstraint.getAllowedValues().size() > 0)
{
element.setAllowedValues(valuesConstraint.getAllowedValues());
}
}
}
}
page.add(element);
}
}
@@ -174,7 +239,8 @@ public class WorkflowRestImpl
ClassDefinition parentClassDefinition = taskType.getParentClassDefinition();
boolean contentClassFound = false;
while(parentClassDefinition != null) {
while(parentClassDefinition != null)
{
if(contentClassFound)
{
typesToExclude.add(parentClassDefinition.getName());
@@ -190,4 +256,72 @@ public class WorkflowRestImpl
}
return typesToExclude;
}
/**
* Validates if the logged in user is allowed to get information about a specific process instance.
* If the user is not allowed an exception is thrown.
*
* @param processId identifier of the process instance
*/
protected void validateIfUserAllowedToWorkWithProcess(String processId)
{
if (tenantService.isEnabled())
{
try
{
String tenantDomain = (String) activitiProcessEngine.getRuntimeService().getVariable(processId, ActivitiConstants.VAR_TENANT_DOMAIN);
if (TenantUtil.getCurrentDomain().equals(tenantDomain) == false)
{
throw new PermissionDeniedException("Process is running in another tenant");
}
}
catch (ActivitiObjectNotFoundException e)
{
throw new EntityNotFoundException(processId);
}
}
try
{
ActivitiScriptNode initiator = (ActivitiScriptNode) activitiProcessEngine.getRuntimeService().getVariable(processId, WorkflowConstants.PROP_INITIATOR);
if (AuthenticationUtil.getRunAsUser().equals(initiator.getNodeRef().getId()))
{
// user is allowed
return;
}
}
catch (ActivitiObjectNotFoundException e)
{
throw new EntityNotFoundException(processId);
}
HistoricTaskInstanceQuery query = activitiProcessEngine.getHistoryService()
.createHistoricTaskInstanceQuery()
.processInstanceId(processId);
if (authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser()))
{
// Admin is allowed to read all processes in the current tenant
if (tenantService.isEnabled())
{
query.processVariableValueEquals(ActivitiConstants.VAR_TENANT_DOMAIN, TenantUtil.getCurrentDomain());
}
else
{
return;
}
}
else
{
// If non-admin user, involvement in the task is required (either owner, assignee or externally involved).
query.taskInvolvedUser(AuthenticationUtil.getRunAsUser());
}
List<HistoricTaskInstance> taskList = query.list();
if(org.apache.commons.collections.CollectionUtils.isEmpty(taskList))
{
throw new PermissionDeniedException("user is not allowed to access information about process " + processId);
}
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.rest.workflow.api.model;
import java.util.Date;
import org.activiti.engine.history.HistoricActivityInstance;
/**
* Representation of an activity in the Activiti engine.
*
* @author Tijs Rademakers
*/
public class Activity
{
String id;
String activityDefinitionId;
String activityDefinitionName;
String activityDefinitionType;
Date startedAt;
Date endedAt;
Long durationInMs;
public Activity(HistoricActivityInstance activity) {
this.id = activity.getId();
this.activityDefinitionId = activity.getActivityId();
this.activityDefinitionName = activity.getActivityName();
this.activityDefinitionType = activity.getActivityType();
this.startedAt = activity.getStartTime();
this.endedAt = activity.getEndTime();
this.durationInMs = activity.getDurationInMillis();
}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getActivityDefinitionId()
{
return activityDefinitionId;
}
public void setActivityDefinitionId(String activityDefinitionId)
{
this.activityDefinitionId = activityDefinitionId;
}
public String getActivityDefinitionName()
{
return activityDefinitionName;
}
public void setActivityDefinitionName(String activityDefinitionName)
{
this.activityDefinitionName = activityDefinitionName;
}
public String getActivityDefinitionType()
{
return activityDefinitionType;
}
public void setActivityDefinitionType(String activityDefinitionType)
{
this.activityDefinitionType = activityDefinitionType;
}
public Date getStartedAt()
{
return startedAt;
}
public void setStartedAt(Date startedAt)
{
this.startedAt = startedAt;
}
public Date getEndedAt()
{
return endedAt;
}
public void setEndedAt(Date endedAt)
{
this.endedAt = endedAt;
}
public Long getDurationInMs()
{
return durationInMs;
}
public void setDurationInMs(Long durationInMs)
{
this.durationInMs = durationInMs;
}
}

View File

@@ -18,6 +18,8 @@
*/
package org.alfresco.rest.workflow.api.model;
import java.util.List;
public class FormModelElement
{
String name;
@@ -26,6 +28,7 @@ public class FormModelElement
String dataType;
boolean required;
String defaultValue;
List<String> allowedValues;
public String getName()
{
@@ -75,4 +78,12 @@ public class FormModelElement
{
this.defaultValue = defaultValue;
}
public List<String> getAllowedValues()
{
return allowedValues;
}
public void setAllowedValues(List<String> allowedValues)
{
this.allowedValues = allowedValues;
}
}

View File

@@ -27,7 +27,8 @@ public class ProcessDefinition
String category;
int version;
String deploymentId;
String title;
String description;
String startFormResourceKey;
Boolean isGraphicNotationDefined;
@@ -38,7 +39,6 @@ public class ProcessDefinition
public ProcessDefinition(org.activiti.engine.repository.ProcessDefinition processDefinition)
{
this.id = processDefinition.getId();
this.key = processDefinition.getKey();
this.name = processDefinition.getName();
this.category = processDefinition.getCategory();
this.version = processDefinition.getVersion();
@@ -104,6 +104,26 @@ public class ProcessDefinition
{
this.deploymentId = deploymentId;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public String getStartFormResourceKey()
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2012 Alfresco Software Limited.
* Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -32,10 +32,14 @@ public class ProcessInfo
String processDefinitionKey;
Date startedAt;
Date endedAt;
Long durationInMillis;
Long durationInMs;
String deleteReason;
String startUserId;
String startActivityId;
String endActivityId;
String businessKey;
String superProcessInstanceId;
boolean completed;
Map<String, Object> variables;
Set<String> items;
@@ -50,9 +54,14 @@ public class ProcessInfo
this.processDefinitionId = processInstance.getProcessDefinitionId();
this.startedAt = processInstance.getStartTime();
this.endedAt = processInstance.getEndTime();
this.durationInMillis = processInstance.getDurationInMillis();
this.durationInMs = processInstance.getDurationInMillis();
this.deleteReason = processInstance.getDeleteReason();
this.startUserId = processInstance.getStartUserId();
this.startActivityId = processInstance.getStartActivityId();
this.endActivityId = processInstance.getEndActivityId();
this.businessKey = processInstance.getBusinessKey();
this.superProcessInstanceId = processInstance.getSuperProcessInstanceId();
this.completed = (processInstance.getEndTime() != null);
}
public String getId()
@@ -75,14 +84,14 @@ public class ProcessInfo
this.processDefinitionId = processDefinitionId;
}
public Long getDurationInMillis()
public Long getDurationInMs()
{
return durationInMillis;
return durationInMs;
}
public void setDurationInMillis(Long durationInMillis)
public void setDurationInMs(Long durationInMs)
{
this.durationInMillis = durationInMillis;
this.durationInMs = durationInMs;
}
public String getDeleteReason()
@@ -145,6 +154,46 @@ public class ProcessInfo
this.endedAt = endedAt;
}
public String getStartUserId()
{
return startUserId;
}
public void setStartUserId(String startUserId)
{
this.startUserId = startUserId;
}
public String getStartActivityId()
{
return startActivityId;
}
public void setStartActivityId(String startActivityId)
{
this.startActivityId = startActivityId;
}
public String getEndActivityId()
{
return endActivityId;
}
public void setEndActivityId(String endActivityId)
{
this.endActivityId = endActivityId;
}
public boolean isCompleted()
{
return completed;
}
public void setCompleted(boolean completed)
{
this.completed = completed;
}
public Map<String, Object> getVariables()
{
return variables;

View File

@@ -21,6 +21,7 @@ package org.alfresco.rest.workflow.api.model;
import java.util.Date;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.task.DelegationState;
public class Task
{
@@ -60,6 +61,18 @@ public class Task
this.owner = taskInstance.getOwner();
this.assignee = taskInstance.getAssignee();
this.formResourceKey = taskInstance.getFormKey();
if (taskInstance.getEndTime() != null)
{
this.state = TaskStateTransition.COMPLETED.name().toLowerCase();
}
else if (taskInstance.getAssignee() != null)
{
this.state = TaskStateTransition.CLAIMED.name().toLowerCase();
}
else
{
this.state = TaskStateTransition.UNCLAIMED.name().toLowerCase();
}
}
public Task(org.activiti.engine.task.Task taskInstance)
@@ -75,6 +88,18 @@ public class Task
this.priority = taskInstance.getPriority();
this.owner = taskInstance.getOwner();
this.assignee = taskInstance.getAssignee();
if (taskInstance.getDelegationState() == DelegationState.PENDING)
{
}
if (taskInstance.getAssignee() != null)
{
this.state = TaskStateTransition.CLAIMED.name().toLowerCase();
}
else
{
this.state = TaskStateTransition.UNCLAIMED.name().toLowerCase();
}
}
public String getId()

View File

@@ -0,0 +1,24 @@
package org.alfresco.rest.workflow.api.model;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
public enum TaskStateTransition {
COMPLETED, CLAIMED, UNCLAIMED, DELEGATED, RESOLVED;
/**
* @return the {@link TaskStateTransition} for the given string
* @throws InvalidArgumentException when no action exists for the given string
*/
public static TaskStateTransition getTaskActionFromString(String action)
{
for(TaskStateTransition taskAction : values())
{
if(taskAction.name().toLowerCase().equals(action))
{
return taskAction;
}
}
throw new InvalidArgumentException("The task state property has an invalid value: " + action);
}
}

View File

@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
@WebApi(name="alfresco", scope=Api.SCOPE.PUBLIC, version=1)
@WebApi(name="workflow", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rest.workflow.api;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;

View File

@@ -18,13 +18,16 @@
*/
package org.alfresco.rest.workflow.api.processdefinitions;
import org.alfresco.rest.framework.BinaryProperties;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.WebApiParameters;
import org.alfresco.rest.framework.core.ResourceParameter;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction;
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.workflow.api.ProcessDefinitions;
@@ -32,7 +35,8 @@ import org.alfresco.rest.workflow.api.model.ProcessDefinition;
@EntityResource(name="process-definitions", title = "Process definitions")
public class ProcessDefinitionsRestEntityResource implements EntityResourceAction.Read<ProcessDefinition>,
EntityResourceAction.ReadById<ProcessDefinition>{
EntityResourceAction.ReadById<ProcessDefinition>,
BinaryResourceAction.Read {
ProcessDefinitions processDefinitions;
@@ -59,4 +63,12 @@ public class ProcessDefinitionsRestEntityResource implements EntityResourceActio
{
return processDefinitions.getProcessDefinition(id);
}
@Override
@WebApiDescription(title = "Get a process definition image", description = "Get a process definition image")
@BinaryProperties({"image"})
public BinaryResource readProperty(String id, Parameters parameters) throws EntityNotFoundException
{
return processDefinitions.getProcessDefinitionImage(id);
}
}

View File

@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
@WebApi(name="alfresco", scope=Api.SCOPE.PUBLIC, version=1)
@WebApi(name="workflow", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rest.workflow.api.processdefinitions;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.rest.workflow.api.processes;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.workflow.api.Activities;
import org.alfresco.rest.workflow.api.model.Activity;
/**
*
* @author Tijs Rademakers
*
*/
@RelationshipResource(name = "activities", entityResource = ProcessesRestEntityResource.class, title = "Activities for the current process")
public class ProcessActivitiesRelation implements RelationshipResourceAction.Read<Activity>
{
protected Activities activities;
public void setActivities(Activities activities)
{
this.activities = activities;
}
/**
* List the activities.
*/
@Override
@WebApiDescription(title = "Get Activities", description = "Get a paged list of the activities")
public CollectionWithPagingInfo<Activity> readAll(String processId, Parameters parameters)
{
return activities.getActivities(processId, parameters);
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.rest.workflow.api.processes;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.workflow.api.Tasks;
import org.alfresco.rest.workflow.api.model.Task;
/**
*
* @author Tijs Rademakers
*
*/
@RelationshipResource(name = "tasks", entityResource = ProcessesRestEntityResource.class, title = "Tasks for the current process")
public class ProcessTasksRelation implements RelationshipResourceAction.Read<Task>
{
protected Tasks tasks;
public void setTasks(Tasks tasks)
{
this.tasks = tasks;
}
/**
* List the tasks.
*/
@Override
@WebApiDescription(title = "Get Tasks", description = "Get a paged list of the tasks")
public CollectionWithPagingInfo<Task> readAll(String processId, Parameters parameters)
{
return tasks.getTasks(processId, parameters);
}
}

View File

@@ -18,6 +18,8 @@
*/
package org.alfresco.rest.workflow.api.processes;
import java.util.List;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
@@ -32,7 +34,7 @@ import org.alfresco.rest.workflow.api.model.Variable;
*
*/
@RelationshipResource(name = "variables", entityResource = ProcessesRestEntityResource.class, title = "Variables for the current process")
public class ProcessVariablesRelation implements RelationshipResourceAction.Read<Variable>,
public class ProcessVariablesRelation implements RelationshipResourceAction.Read<Variable>, RelationshipResourceAction.Create<Variable>,
RelationshipResourceAction.Update<Variable>, RelationshipResourceAction.Delete
{
protected Processes processes;
@@ -51,6 +53,16 @@ public class ProcessVariablesRelation implements RelationshipResourceAction.Read
{
return processes.getVariables(processId, parameters.getPaging());
}
/**
* Creates or updates multiple variables. If the variable name doesn't exist yet it will be created
*/
@Override
@WebApiDescription(title = "Create or Update Variables", description = "Create or update multiple variable")
public List<Variable> create(String processId, List<Variable> variables, Parameters parameters)
{
return processes.updateVariables(processId, variables);
}
/**
* Update a variable. If the variable name doesn't exist yet it will be created

View File

@@ -27,7 +27,6 @@ import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.WebApiParameters;
import org.alfresco.rest.framework.core.ResourceParameter;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction;
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
@@ -79,16 +78,11 @@ public class ProcessesRestEntityResource implements EntityResourceAction.Read<Pr
}
@Override
@WebApiDescription(title = "Updates a flocket")
@BinaryProperties({"images"})
public BinaryResource readProperty(String entityId, Parameters parameters)
throws EntityNotFoundException
@WebApiDescription(title = "Get a process instance image", description = "Get a process instance image")
@BinaryProperties({"image"})
public BinaryResource readProperty(String entityId, Parameters parameters) throws EntityNotFoundException
{
if(parameters.hasBinaryProperty("image"))
{
return processes.getProcessImage(entityId);
}
throw new InvalidArgumentException("Only image is supported property");
return processes.getProcessImage(entityId);
}
@Override

View File

@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
@WebApi(name="alfresco", scope=Api.SCOPE.PUBLIC, version=1)
@WebApi(name="workflow", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rest.workflow.api.processes;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;

View File

@@ -18,6 +18,8 @@
*/
package org.alfresco.rest.workflow.api.tasks;
import java.util.List;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
@@ -35,7 +37,7 @@ import org.alfresco.rest.workflow.api.model.VariableScope;
*
*/
@RelationshipResource(name = "variables", entityResource = TasksRestEntityResource.class, title = "Variables for the current task")
public class TaskVariablesRelation implements RelationshipResourceAction.Read<TaskVariable>,
public class TaskVariablesRelation implements RelationshipResourceAction.Read<TaskVariable>, RelationshipResourceAction.Create<TaskVariable>,
RelationshipResourceAction.Update<TaskVariable>, RelationshipResourceAction.Delete
{
private Tasks tasks;
@@ -64,6 +66,16 @@ public class TaskVariablesRelation implements RelationshipResourceAction.Read<Ta
}
return tasks.getTaskVariables(taskId, parameters.getPaging(), scope);
}
/**
* Creates or updates multiple task variables. If the variable name doesn't exist yet it will be created
*/
@Override
@WebApiDescription(title = "Create or Update Variables", description = "Create or update multiple variable")
public List<TaskVariable> create(String taskId, List<TaskVariable> variables, Parameters parameters)
{
return tasks.updateTaskVariables(taskId, variables);
}
/**
* Update a task variable. If the variable name doesn't exist yet it will be created

View File

@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
@WebApi(name="alfresco", scope=Api.SCOPE.PUBLIC, version=1)
@WebApi(name="workflow", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rest.workflow.api.tasks;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;