From 75065e6daace0c9e8f90746158a256306ca260ba Mon Sep 17 00:00:00 2001 From: Gavin Cornwell Date: Tue, 3 Aug 2010 13:21:31 +0000 Subject: [PATCH] Merged BRANCHES/DEV/BELARUS/HEAD_2010_07_29 to HEAD: 21523: ALF-3895 : F66 REST API to get a specific workflow instance git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21569 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../alfresco/repository/workflow/task.lib.ftl | 69 +++-- .../workflow/workflow-definition.lib.ftl | 17 +- .../workflow/workflow-instance.get.desc.xml | 8 + .../workflow/workflow-instance.get.json.ftl | 6 + .../web-scripts-application-context.xml | 5 + .../workflow/AbstractWorkflowWebscript.java | 2 +- .../scripts/workflow/WorkflowInstanceGet.java | 86 ++++++ .../workflow/WorkflowModelBuilder.java | 250 ++++++++++++++---- .../workflow/WorkflowModelBuilderTest.java | 72 ++++- .../scripts/workflow/WorkflowRestApiTest.java | 63 +++++ 10 files changed, 498 insertions(+), 80 deletions(-) create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-instance.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-instance.get.json.ftl create mode 100644 source/java/org/alfresco/repo/web/scripts/workflow/WorkflowInstanceGet.java diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/task.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/task.lib.ftl index 6760864ded..da0a78fa51 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/task.lib.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/task.lib.ftl @@ -1,3 +1,5 @@ +<#import "workflow-definition.lib.ftl" as worflowDefinitionLib /> + <#-- Renders a task instance. --> <#macro taskJSON task detailed=false> <#escape x as jsonUtils.encodeJSONString(x)> @@ -24,28 +26,7 @@ <@propertiesJSON properties=task.properties /> <#if detailed>, "path": "${task.path}", - "workflowInstance": - { - "id": "${task.workflowInstance.id}", - "url": "${task.workflowInstance.url}", - "name": "${task.workflowInstance.name}", - "title": "${task.workflowInstance.title}", - "description": "${task.workflowInstance.description}", - "isActive": ${task.workflowInstance.isActive?string}, - "startDate": "${task.workflowInstance.startDate}", - "endDate": <#if task.workflowInstance.endDate??>"${task.workflowInstance.endDate}"<#else>null, - "initiator": - <#if task.workflowInstance.initiator??> - { - "userName": "${task.workflowInstance.initiator.userName}", - "firstName": "${task.workflowInstance.initiator.firstName}", - "lastName": "${task.workflowInstance.initiator.lastName}" - }, - <#else> - null, - - "definitionUrl": "${task.workflowInstance.definitionUrl}" - }, + "workflowInstance": <@workflowInstanceJSON workflowInstance=task.workflowInstance/>, "definition": { "id": "${task.definition.id}", @@ -112,3 +93,47 @@ } + +<#-- Renders a workflow instance. --> +<#macro workflowInstanceJSON workflowInstance detailed=false> +<#escape x as jsonUtils.encodeJSONString(x)> + { + "id": "${workflowInstance.id}", + "url": "${workflowInstance.url}", + "name": "${workflowInstance.name}", + "title": "${workflowInstance.title}", + "description": "${workflowInstance.description}", + "isActive": ${workflowInstance.isActive?string}, + "startDate": "${workflowInstance.startDate}", + "endDate": <#if workflowInstance.endDate??>"${workflowInstance.endDate}"<#else>null, + "initiator": + <#if workflowInstance.initiator??> + { + "userName": "${workflowInstance.initiator.userName}", + "firstName": "${workflowInstance.initiator.firstName}", + "lastName": "${workflowInstance.initiator.lastName}" + }, + <#else> + null, + + "definitionUrl": "${workflowInstance.definitionUrl}" + <#if detailed>, + "dueDate": <#if workflowInstance.dueDate??>"${workflowInstance.dueDate}"<#else>null, + "priority": <#if workflowInstance.priority??>${workflowInstance.priority?c}<#else>null, + "context": <#if workflowInstance.context??>"${workflowInstance.context}"<#else>null, + "package": "${workflowInstance.package}", + "startTaskInstanceId": "${workflowInstance.startTaskInstanceId}", + "definition": <@worflowDefinitionLib.workflowDefinitionJSON workflowDefinition=workflowInstance.definition detailed=true/> + <#if workflowInstance.tasks??>, + "tasks": + [ + <#list workflowInstance.tasks as task> + <@taskJSON task=task/> + <#if task_has_next>, + + ] + + + } + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-definition.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-definition.lib.ftl index 8674e9880f..c1a6a80275 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-definition.lib.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-definition.lib.ftl @@ -1,5 +1,5 @@ <#-- Renders a workflow definition. --> -<#macro workflowDefinitionJSON workflowDefinition> +<#macro workflowDefinitionJSON workflowDefinition detailed=false> <#escape x as jsonUtils.encodeJSONString(x)> { "id" : "${workflowDefinition.id}", @@ -7,6 +7,21 @@ "name": "${workflowDefinition.name}", "title": "${workflowDefinition.title}", "description": "${workflowDefinition.description}" + <#if detailed>, + "version": "${workflowDefinition.version}", + "startTaskDefinitionUrl": "${workflowDefinition.startTaskDefinitionUrl}", + "startTaskDefinitionType": "${shortQName(workflowDefinition.startTaskDefinitionType)}", + "taskDefinitions": + [ + <#list workflowDefinition.taskDefinitions as taskDefinition> + { + "url": "${taskDefinition.url}", + "type": "${shortQName(taskDefinition.type)}" + } + <#if taskDefinition_has_next>, + + ] + } \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-instance.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-instance.get.desc.xml new file mode 100644 index 0000000000..e7da1fd660 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-instance.get.desc.xml @@ -0,0 +1,8 @@ + + Get Workflow Instance + Retrieves a specific workflow instance, optionally with all the tasks. + /api/workflow-instances/{workflow_instance_id}?includeTasks={includeTasks?} + + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-instance.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-instance.get.json.ftl new file mode 100644 index 0000000000..8da05e3f60 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/workflow/workflow-instance.get.json.ftl @@ -0,0 +1,6 @@ +<#-- Workflow Instance in details --> + +<#import "task.lib.ftl" as taskLib /> +{ + "data": <@taskLib.workflowInstanceJSON workflowInstance=workflowInstance detailed=true/> +} \ No newline at end of file diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 3fd10b4592..c0edbc988d 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -811,6 +811,11 @@ class="org.alfresco.repo.web.scripts.workflow.WorkflowDefinitionsGet" parent="abstractWorkflowWebScript"> + + + diff --git a/source/java/org/alfresco/repo/web/scripts/workflow/AbstractWorkflowWebscript.java b/source/java/org/alfresco/repo/web/scripts/workflow/AbstractWorkflowWebscript.java index c60654df0a..434845c8d7 100644 --- a/source/java/org/alfresco/repo/web/scripts/workflow/AbstractWorkflowWebscript.java +++ b/source/java/org/alfresco/repo/web/scripts/workflow/AbstractWorkflowWebscript.java @@ -48,7 +48,7 @@ public abstract class AbstractWorkflowWebscript extends DeclarativeWebScript @Override protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) { - WorkflowModelBuilder modelBuilder = new WorkflowModelBuilder(namespaceService, nodeService, personService); + WorkflowModelBuilder modelBuilder = new WorkflowModelBuilder(namespaceService, nodeService, personService, workflowService); return buildModel(modelBuilder, req, status, cache); } diff --git a/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowInstanceGet.java b/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowInstanceGet.java new file mode 100644 index 0000000000..a216836a78 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowInstanceGet.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2005-2010 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 . + */ +package org.alfresco.repo.web.scripts.workflow; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.service.cmr.workflow.WorkflowInstance; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * @author unknown + * @since 3.4 + * + */ +public class WorkflowInstanceGet extends AbstractWorkflowWebscript +{ + + public static final String PARAM_INCLUDE_TASKS = "includeTasks"; + + @Override + protected Map buildModel(WorkflowModelBuilder modelBuilder, WebScriptRequest req, Status status, Cache cache) + { + Map params = req.getServiceMatch().getTemplateVars(); + + // getting workflow instance id from request parameters + String workflowInstanceId = params.get("workflow_instance_id"); + + boolean includeTasks = getIncludeTasks(req); + + WorkflowInstance workflowInstance = workflowService.getWorkflowById(workflowInstanceId); + + // task was not found -> return 404 + if (workflowInstance == null) + { + throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find workflow instance with id: " + workflowInstanceId); + } + + Map model = new HashMap(); + // build the model for ftl + model.put("workflowInstance", modelBuilder.buildDetailed(workflowInstance, includeTasks)); + + return model; + } + + private boolean getIncludeTasks(WebScriptRequest req) + { + String includeTasks = req.getParameter(PARAM_INCLUDE_TASKS); + if (includeTasks != null) + { + try + { + return Boolean.valueOf(includeTasks); + } + catch (Exception e) + { + // do nothing, false will be returned + } + } + + // Defaults to false. + return false; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowModelBuilder.java b/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowModelBuilder.java index 097518db6e..9df8931afa 100644 --- a/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowModelBuilder.java +++ b/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowModelBuilder.java @@ -22,6 +22,7 @@ import java.io.Serializable; 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; @@ -42,8 +43,11 @@ import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowInstance; import org.alfresco.service.cmr.workflow.WorkflowNode; import org.alfresco.service.cmr.workflow.WorkflowPath; +import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowTask; import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition; +import org.alfresco.service.cmr.workflow.WorkflowTaskQuery; +import org.alfresco.service.cmr.workflow.WorkflowTaskState; import org.alfresco.service.cmr.workflow.WorkflowTransition; import org.alfresco.service.namespace.NamespaceException; import org.alfresco.service.namespace.NamespaceService; @@ -87,8 +91,15 @@ public class WorkflowModelBuilder public static final String TASK_WORKFLOW_INSTANCE_DESCRIPTION = "description"; public static final String TASK_WORKFLOW_INSTANCE_IS_ACTIVE = "isActive"; public static final String TASK_WORKFLOW_INSTANCE_START_DATE = "startDate"; + public static final String TASK_WORKFLOW_INSTANCE_DUE_DATE = "dueDate"; public static final String TASK_WORKFLOW_INSTANCE_END_DATE = "endDate"; + public static final String TASK_WORKFLOW_INSTANCE_PRIORITY = "priority"; public static final String TASK_WORKFLOW_INSTANCE_INITIATOR = "initiator"; + public static final String TASK_WORKFLOW_INSTANCE_CONTEXT = "context"; + public static final String TASK_WORKFLOW_INSTANCE_PACKAGE = "package"; + public static final String TASK_WORKFLOW_INSTANCE_START_TASK_INSTANCE_ID = "startTaskInstanceId"; + public static final String TASK_WORKFLOW_INSTANCE_DEFINITION = "definition"; + public static final String TASK_WORKFLOW_INSTANCE_TASKS = "tasks"; public static final String TASK_WORKFLOW_INSTANCE_DEFINITION_URL = "definitionUrl"; public static final String TASK_WORKFLOW_INSTANCE_INITIATOR_USERNAME = "userName"; @@ -117,18 +128,24 @@ public class WorkflowModelBuilder public static final String WORKFLOW_DEFINITION_NAME = "name"; public static final String WORKFLOW_DEFINITION_TITLE = "title"; public static final String WORKFLOW_DEFINITION_DESCRIPTION = "description"; + public static final String WORKFLOW_DEFINITION_VERSION = "version"; + public static final String WORKFLOW_DEFINITION_START_TASK_DEFINITION_URL = "startTaskDefinitionUrl"; + public static final String WORKFLOW_DEFINITION_START_TASK_DEFINITION_TYPE = "startTaskDefinitionType"; + public static final String WORKFLOW_DEFINITION_TASK_DEFINITIONS = "taskDefinitions"; private static final String PREFIX_SEPARATOR = Character.toString(QName.NAMESPACE_PREFIX); private final NamespaceService namespaceService; private final NodeService nodeService; private final PersonService personService; + private final WorkflowService workflowService; - public WorkflowModelBuilder(NamespaceService namespaceService, NodeService nodeService, PersonService personService) + public WorkflowModelBuilder(NamespaceService namespaceService, NodeService nodeService, PersonService personService, WorkflowService workflowService) { this.namespaceService = namespaceService; this.nodeService = nodeService; this.personService = personService; + this.workflowService = workflowService; } /** @@ -168,10 +185,148 @@ public class WorkflowModelBuilder model.put(TASK_PATH, getUrl(workflowTask.getPath())); // workflow instance part - model.put(TASK_WORKFLOW_INSTANCE, buildWorkflowInstance(workflowTask.path.instance)); + model.put(TASK_WORKFLOW_INSTANCE, buildSimple(workflowTask.getPath().getInstance())); // definition part - model.put(TASK_DEFINITION, buildTaskDefinition(workflowTask.definition, workflowTask)); + model.put(TASK_DEFINITION, buildTaskDefinition(workflowTask.getDefinition(), workflowTask)); + + return model; + } + + /** + * Returns a simple representation of a {@link WorkflowInstance}. + * @param workflowInstance The workflow instance to be represented. + * @return + */ + public Map buildSimple(WorkflowInstance workflowInstance) + { + Map model = new HashMap(); + + model.put(TASK_WORKFLOW_INSTANCE_ID, workflowInstance.getId()); + model.put(TASK_WORKFLOW_INSTANCE_URL, getUrl(workflowInstance)); + model.put(TASK_WORKFLOW_INSTANCE_NAME, workflowInstance.getDefinition().getName()); + model.put(TASK_WORKFLOW_INSTANCE_TITLE, workflowInstance.getDefinition().getTitle()); + model.put(TASK_WORKFLOW_INSTANCE_DESCRIPTION, workflowInstance.getDefinition().getDescription()); + model.put(TASK_WORKFLOW_INSTANCE_IS_ACTIVE, workflowInstance.isActive()); + + if (workflowInstance.getStartDate() == null) + { + model.put(TASK_WORKFLOW_INSTANCE_START_DATE, workflowInstance.getStartDate()); + } + else + { + model.put(TASK_WORKFLOW_INSTANCE_START_DATE, ISO8601DateFormat.format(workflowInstance.getStartDate())); + } + + if (workflowInstance.getEndDate() == null) + { + model.put(TASK_WORKFLOW_INSTANCE_END_DATE, workflowInstance.getEndDate()); + } + else + { + model.put(TASK_WORKFLOW_INSTANCE_END_DATE, ISO8601DateFormat.format(workflowInstance.getEndDate())); + } + + if (workflowInstance.getInitiator() == null) + { + model.put(TASK_WORKFLOW_INSTANCE_INITIATOR, null); + } + else + { + model.put(TASK_WORKFLOW_INSTANCE_INITIATOR, getPersonModel(nodeService.getProperty(workflowInstance.initiator, ContentModel.PROP_USERNAME))); + } + model.put(TASK_WORKFLOW_INSTANCE_DEFINITION_URL, getUrl(workflowInstance.getDefinition())); + + return model; + } + + /** + * Returns a detailed representation of a {@link WorkflowInstance}. + * @param workflowInstance The workflow instance to be represented. + * @param includeTasks should we include task in model? + * @return + */ + public Map buildDetailed(WorkflowInstance workflowInstance, boolean includeTasks) + { + Map model = buildSimple(workflowInstance); + + Serializable dueDate = null; + Serializable priority = null; + Serializable startTaskId = null; + + // get all active tasks + List activeTasks = workflowService.queryTasks(new WorkflowTaskQuery()); + // get all completed tasks + WorkflowTaskQuery completedTasksQuery = new WorkflowTaskQuery(); + completedTasksQuery.setTaskState(WorkflowTaskState.COMPLETED); + completedTasksQuery.setActive(null); + List completedTasks = workflowService.queryTasks(completedTasksQuery); + + ArrayList> results = new ArrayList>(); + + for (WorkflowTask completedTask : completedTasks) + { + if (completedTask.path.instance.id.equals(workflowInstance.id)) + { + if (completedTask.properties.get(WorkflowModel.PROP_DUE_DATE) != null) + { + dueDate = completedTask.properties.get(WorkflowModel.PROP_DUE_DATE); + } + if (completedTask.properties.get(WorkflowModel.PROP_PRIORITY) != null) + { + priority = completedTask.properties.get(WorkflowModel.PROP_PRIORITY); + } + if (workflowInstance.definition.getStartTaskDefinition().id.equals(completedTask.definition.id)) + { + startTaskId = completedTask.id; + } + results.add(buildSimple(completedTask, null)); + } + } + + for (WorkflowTask activeTask : activeTasks) + { + if (activeTask.path.instance.id.equals(workflowInstance.id)) + { + if (activeTask.properties.get(WorkflowModel.PROP_DUE_DATE) != null) + { + dueDate = activeTask.properties.get(WorkflowModel.PROP_DUE_DATE); + } + if (activeTask.properties.get(WorkflowModel.PROP_PRIORITY) != null) + { + priority = activeTask.properties.get(WorkflowModel.PROP_PRIORITY); + } + if (workflowInstance.definition.getStartTaskDefinition().id.equals(activeTask.definition.id)) + { + startTaskId = activeTask.id; + } + results.add(buildSimple(activeTask, null)); + } + } + + if (includeTasks) + { + model.put(TASK_WORKFLOW_INSTANCE_TASKS, results); + } + + if (dueDate != null) + { + model.put(TASK_WORKFLOW_INSTANCE_DUE_DATE, ISO8601DateFormat.format((Date) dueDate)); + } + else + { + model.put(TASK_WORKFLOW_INSTANCE_DUE_DATE, dueDate); + } + + if (workflowInstance.context != null) + { + model.put(TASK_WORKFLOW_INSTANCE_CONTEXT, workflowInstance.context.toString()); + } + + model.put(TASK_WORKFLOW_INSTANCE_PRIORITY, priority); + model.put(TASK_WORKFLOW_INSTANCE_PACKAGE, workflowInstance.workflowPackage.toString()); + model.put(TASK_WORKFLOW_INSTANCE_START_TASK_INSTANCE_ID, startTaskId); + model.put(TASK_WORKFLOW_INSTANCE_DEFINITION, buildDetailed(workflowInstance.definition)); return model; } @@ -195,6 +350,40 @@ public class WorkflowModelBuilder return model; } + /** + * Returns a detailed representation of a {@link WorkflowDefinition}. + * + * @param workflowDefinition the WorkflowDefinition object to be represented. + * @return + */ + public Map buildDetailed(WorkflowDefinition workflowDefinition) + { + Map model = buildSimple(workflowDefinition); + + model.put(WORKFLOW_DEFINITION_VERSION, workflowDefinition.getVersion()); + model.put(WORKFLOW_DEFINITION_START_TASK_DEFINITION_URL, getUrl(workflowDefinition.getStartTaskDefinition().getMetadata())); + model.put(WORKFLOW_DEFINITION_START_TASK_DEFINITION_TYPE, workflowDefinition.getStartTaskDefinition().getMetadata().getName()); + + ArrayList> results = new ArrayList>(); + for (WorkflowTaskDefinition taskDefinition : workflowService.getTaskDefinitions(workflowDefinition.getId())) + { + if (taskDefinition.id.equals(workflowDefinition.getStartTaskDefinition().getId())) + { + continue; + } + + Map result = new HashMap(); + + result.put(TASK_DEFINITION_URL, getUrl(taskDefinition.getMetadata())); + result.put(TASK_DEFINITION_TYPE, taskDefinition.getMetadata().getName()); + + results.add(result); + } + model.put(WORKFLOW_DEFINITION_TASK_DEFINITIONS, results); + + return model; + } + private Object isPooled(Map properties) { Collection actors = (Collection) properties.get(WorkflowModel.ASSOC_POOLED_ACTORS); @@ -240,6 +429,7 @@ public class WorkflowModelBuilder { return value; } + if (value instanceof Collection) { Collection collection = (Collection) value; @@ -250,6 +440,7 @@ public class WorkflowModelBuilder } return results; } + return DefaultTypeConverter.INSTANCE.convert(String.class, value); } @@ -289,48 +480,6 @@ public class WorkflowModelBuilder return model; } - private Map buildWorkflowInstance(WorkflowInstance workflowInstance) - { - Map model = new HashMap(); - - model.put(TASK_WORKFLOW_INSTANCE_ID, workflowInstance.id); - model.put(TASK_WORKFLOW_INSTANCE_URL, getUrl(workflowInstance)); - model.put(TASK_WORKFLOW_INSTANCE_NAME, workflowInstance.definition.name); - model.put(TASK_WORKFLOW_INSTANCE_TITLE, workflowInstance.definition.title); - model.put(TASK_WORKFLOW_INSTANCE_DESCRIPTION, workflowInstance.definition.description); - model.put(TASK_WORKFLOW_INSTANCE_IS_ACTIVE, workflowInstance.active); - - if (workflowInstance.startDate == null) - { - model.put(TASK_WORKFLOW_INSTANCE_START_DATE, workflowInstance.startDate); - } - else - { - model.put(TASK_WORKFLOW_INSTANCE_START_DATE, ISO8601DateFormat.format(workflowInstance.startDate)); - } - - if (workflowInstance.endDate == null) - { - model.put(TASK_WORKFLOW_INSTANCE_END_DATE, workflowInstance.endDate); - } - else - { - model.put(TASK_WORKFLOW_INSTANCE_END_DATE, ISO8601DateFormat.format(workflowInstance.endDate)); - } - - if (workflowInstance.initiator == null) - { - model.put(TASK_WORKFLOW_INSTANCE_INITIATOR, null); - } - else - { - model.put(TASK_WORKFLOW_INSTANCE_INITIATOR, getPersonModel(nodeService.getProperty(workflowInstance.initiator, ContentModel.PROP_USERNAME))); - } - model.put(TASK_WORKFLOW_INSTANCE_DEFINITION_URL, getUrl(workflowInstance.definition)); - - return model; - } - private Map buildTaskDefinition(WorkflowTaskDefinition workflowTaskDefinition, WorkflowTask workflowTask) { Map model = new HashMap(); @@ -382,9 +531,11 @@ public class WorkflowModelBuilder private List getHiddenTransitions(Map properties) { Serializable hiddenSer = properties.get(WorkflowModel.PROP_HIDDEN_TRANSITIONS); - if(hiddenSer instanceof List) + if (hiddenSer instanceof List) + { return (List) hiddenSer; - else if(hiddenSer instanceof String) + } + else if (hiddenSer instanceof String) { String hiddenStr = (String) hiddenSer; return Arrays.asList(hiddenStr.split(",")); @@ -399,15 +550,16 @@ public class WorkflowModelBuilder model.put(WORKFLOW_NODE_TRANSITION_ID, id); model.put(WORKFLOW_NODE_TRANSITION_TITLE, workflowTransition.getTitle()); model.put(WORKFLOW_NODE_TRANSITION_DESCRIPTION, workflowTransition.getDescription()); - model.put(WORKFLOW_NODE_TRANSITION_IS_DEFAULT, workflowTransition.isDefault); + model.put(WORKFLOW_NODE_TRANSITION_IS_DEFAULT, workflowTransition.isDefault()); model.put(WORKFLOW_NODE_TRANSITION_IS_HIDDEN, isHiddenTransition(id, hiddenTransitions)); return model; } private boolean isHiddenTransition(String transitionId, List hiddenTransitions) { - if(hiddenTransitions == null) + if (hiddenTransitions == null) return false; + return hiddenTransitions.contains(transitionId); } diff --git a/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowModelBuilderTest.java b/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowModelBuilderTest.java index acc8f8b4dc..68ef3ff13b 100644 --- a/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowModelBuilderTest.java +++ b/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowModelBuilderTest.java @@ -42,6 +42,7 @@ import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowInstance; import org.alfresco.service.cmr.workflow.WorkflowNode; import org.alfresco.service.cmr.workflow.WorkflowPath; +import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowTask; import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition; import org.alfresco.service.cmr.workflow.WorkflowTaskState; @@ -62,10 +63,12 @@ public class WorkflowModelBuilderTest extends TestCase private static final String firstName = "Joe"; private static final String lastName = "Bloggs"; private static final NodeRef person = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, userName); + private static final NodeRef workflowPackage = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "workflowPackage"); private NamespaceService namespaceService; private PersonService personService; private NodeService nodeService; + private WorkflowService workflowService; private WorkflowModelBuilder builder; @SuppressWarnings("unchecked") @@ -199,13 +202,50 @@ public class WorkflowModelBuilderTest extends TestCase WorkflowDefinition workflowDefinition = new WorkflowDefinition("The Id", "The Name", "The Version", "The Title", "The Description", workflowTaskDefinition); Map model = builder.buildSimple(workflowDefinition); - assertEquals(workflowDefinition.id, model.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_ID)); - assertEquals("api/workflow-definitions/" + workflowDefinition.id, model.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_URL)); - assertEquals(workflowDefinition.name, model.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_NAME)); - assertEquals(workflowDefinition.title, model.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_TITLE)); - assertEquals(workflowDefinition.description, model.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_DESCRIPTION)); + assertEquals(workflowDefinition.getId(), model.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_ID)); + assertEquals("api/workflow-definitions/" + workflowDefinition.getId(), model.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_URL)); + assertEquals(workflowDefinition.getName(), model.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_NAME)); + assertEquals(workflowDefinition.getTitle(), model.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_TITLE)); + assertEquals(workflowDefinition.getDescription(), model.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_DESCRIPTION)); } - + + @SuppressWarnings("unchecked") + public void testBuildWorkflowInstanceDetailed() throws Exception + { + WorkflowTaskDefinition workflowTaskDefinition = new WorkflowTaskDefinition(); + workflowTaskDefinition.metadata = mock(TypeDefinition.class); + when(workflowTaskDefinition.getMetadata().getName()).thenReturn(QName.createQName("The Type Name")); + when(workflowTaskDefinition.getMetadata().getTitle()).thenReturn("The Type Title"); + when(workflowTaskDefinition.getMetadata().getDescription()).thenReturn("The Type Description"); + + WorkflowInstance workflowInstance = makeWorkflowInstance(workflowTaskDefinition); + + Map model = builder.buildDetailed(workflowInstance, true); + + assertEquals(workflowInstance.getId(), model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_ID)); + assertEquals(workflowInstance.getDefinition().getName(), model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_NAME)); + assertEquals(workflowInstance.getDefinition().getTitle(), model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_TITLE)); + assertEquals(workflowInstance.getDefinition().getDescription(), model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_DESCRIPTION)); + assertEquals(workflowInstance.isActive(), model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_IS_ACTIVE)); + assertEquals(ISO8601DateFormat.format(workflowInstance.getStartDate()), model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_START_DATE)); + assertEquals(ISO8601DateFormat.format(workflowInstance.getEndDate()), model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_END_DATE)); + + Map initiator = (Map) model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_INITIATOR); + assertEquals(userName, initiator.get(WorkflowModelBuilder.PERSON_USER_NAME)); + assertEquals(firstName, initiator.get(WorkflowModelBuilder.PERSON_FIRST_NAME)); + assertEquals(lastName, initiator.get(WorkflowModelBuilder.PERSON_LAST_NAME)); + + assertEquals(workflowInstance.getContext().toString(), model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_CONTEXT)); + assertEquals(workflowInstance.getWorkflowPackage().toString(), model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_PACKAGE)); + + Map taskInstanceModel = (Map) model.get(WorkflowModelBuilder.TASK_WORKFLOW_INSTANCE_DEFINITION); + + assertEquals(workflowInstance.getDefinition().getVersion(), taskInstanceModel.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_VERSION)); + assertEquals(workflowInstance.getDefinition().getStartTaskDefinition().getMetadata().getName(), + taskInstanceModel.get(WorkflowModelBuilder.WORKFLOW_DEFINITION_START_TASK_DEFINITION_TYPE)); + + } + private WorkflowNode makeNode() { WorkflowNode node = new WorkflowNode(); @@ -273,6 +313,21 @@ public class WorkflowModelBuilderTest extends TestCase task.properties = makeTaskProperties(date); return task; } + + private WorkflowInstance makeWorkflowInstance(WorkflowTaskDefinition taskDefinition) + { + WorkflowInstance workflowInstance = new WorkflowInstance(); + workflowInstance.id = "The id"; + workflowInstance.active = true; + workflowInstance.startDate = new Date(); + workflowInstance.endDate = new Date(); + workflowInstance.initiator = person; + workflowInstance.definition = new WorkflowDefinition( + "The Id", "The Name", "The Version", "The Title", "The Description", taskDefinition); + workflowInstance.workflowPackage = workflowPackage; + workflowInstance.context = workflowPackage; + return workflowInstance; + } private HashMap makeTaskProperties(Date date) { @@ -307,7 +362,10 @@ public class WorkflowModelBuilderTest extends TestCase personProps.put(ContentModel.PROP_FIRSTNAME, firstName); personProps.put(ContentModel.PROP_LASTNAME, lastName); when(nodeService.getProperties(person)).thenReturn(personProps); + when(nodeService.getProperty(person, ContentModel.PROP_USERNAME)).thenReturn(userName); - builder = new WorkflowModelBuilder(namespaceService, nodeService, personService); + workflowService = mock(WorkflowService.class); + + builder = new WorkflowModelBuilder(namespaceService, nodeService, personService, workflowService); } } diff --git a/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowRestApiTest.java b/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowRestApiTest.java index 394643ed1e..d2696df181 100644 --- a/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowRestApiTest.java +++ b/source/java/org/alfresco/repo/web/scripts/workflow/WorkflowRestApiTest.java @@ -65,6 +65,7 @@ public class WorkflowRestApiTest extends BaseWebScriptTest private final static String USER3 = "Nick" + GUID.generate(); private static final String URL_TASKS = "api/task-instances"; private static final String URL_WORKFLOW_DEFINITIONS = "api/workflow-definitions"; + private static final String URL_WORKFLOW_INSTANCES = "api/workflow-instances"; private TestPersonManager personManager; private WorkflowService workflowService; @@ -313,6 +314,68 @@ public class WorkflowRestApiTest extends BaseWebScriptTest } } + public void testWorkflowInstanceGet() throws Exception + { + //Start workflow as USER1 and assign task to USER2. + personManager.setUser(USER1); + WorkflowDefinition adhocDef = workflowService.getDefinitionByName("jbpm$wf:adhoc"); + Map params = new HashMap(); + params.put(WorkflowModel.ASSOC_ASSIGNEE, personManager.get(USER2)); + Date dueDate = new Date(); + params.put(WorkflowModel.PROP_DUE_DATE, dueDate); + params.put(WorkflowModel.PROP_PRIORITY, 1); + params.put(WorkflowModel.ASSOC_PACKAGE, packageRef); + params.put(WorkflowModel.PROP_CONTEXT, packageRef); + + WorkflowPath adhocPath = workflowService.startWorkflow(adhocDef.id, params); + WorkflowTask startTask = workflowService.getTasksForWorkflowPath(adhocPath.id).get(0); + startTask = workflowService.endTask(startTask.id, null); + + WorkflowInstance adhocInstance = startTask.path.instance; + + Response response = sendRequest(new GetRequest(URL_WORKFLOW_INSTANCES + "/" + adhocInstance.id + "?includeTasks=true"), 200); + assertEquals(Status.STATUS_OK, response.getStatus()); + String jsonStr = response.getContentAsString(); + JSONObject json = new JSONObject(jsonStr); + JSONObject result = json.getJSONObject("data"); + assertNotNull(result); + + assertEquals(adhocInstance.id, result.getString("id")); + assertEquals(adhocInstance.definition.name, result.getString("name")); + assertEquals(adhocInstance.definition.title, result.getString("title")); + assertEquals(adhocInstance.definition.description, result.getString("description")); + assertEquals(adhocInstance.active, result.getBoolean("isActive")); + assertEquals(ISO8601DateFormat.format(adhocInstance.startDate), result.getString("startDate")); + assertNotNull(result.getString("dueDate")); + assertNotNull(result.getString("endDate")); + assertEquals(2, result.getInt("priority")); + JSONObject initiator = result.getJSONObject("initiator"); + + assertEquals(USER1, initiator.getString("userName")); + assertEquals(personManager.getFirstName(USER1), initiator.getString("firstName")); + assertEquals(personManager.getLastName(USER1), initiator.getString("lastName")); + + assertEquals(adhocInstance.context.toString(), result.getString("context")); + assertEquals(adhocInstance.workflowPackage.toString(), result.getString("package")); + assertNotNull(result.getString("startTaskInstanceId")); + + JSONObject jsonDefinition = result.getJSONObject("definition"); + WorkflowDefinition adhocDefinition = adhocInstance.definition; + + assertNotNull(jsonDefinition); + + assertEquals(adhocDefinition.id, jsonDefinition.getString("id")); + assertEquals(adhocDefinition.name, jsonDefinition.getString("name")); + assertEquals(adhocDefinition.title, jsonDefinition.getString("title")); + assertEquals(adhocDefinition.description, jsonDefinition.getString("description")); + assertEquals(adhocDefinition.version, jsonDefinition.getString("version")); + assertEquals(adhocDefinition.getStartTaskDefinition().metadata.getName().toPrefixString(namespaceService), jsonDefinition.getString("startTaskDefinitionType")); + assertTrue(jsonDefinition.has("taskDefinitions")); + + JSONArray tasks = result.getJSONArray("tasks"); + assertTrue(tasks.length() > 1); + } + @Override protected void setUp() throws Exception {