Implemented temporary workflow form processor and associated test.

An item kind of "workflow" and itemId of "<workflow-def-name>" are now supported (only "jbpm$wf:adhoc" works though at the moment). Showing the form, selecting an assignee and submitting the form will start the ad hoc workflow and create a task for the selected assignee.

NOTE: Support for 'packageItems' is not present yet.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21021 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gavin Cornwell
2010-07-08 22:46:52 +00:00
parent 5cc26951f4
commit a2f410e5a2
2 changed files with 312 additions and 2 deletions

View File

@@ -44,6 +44,10 @@ import org.alfresco.service.cmr.repository.ScriptLocation;
import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.workflow.WorkflowInstance;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
import org.alfresco.service.namespace.NamespaceException;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
@@ -64,6 +68,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
private ScriptService scriptService;
private PersonService personService;
private ContentService contentService;
private WorkflowService workflowService;
private NodeRef document;
private NodeRef associatedDoc;
@@ -106,6 +111,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
private static final String USER_ONE = "UserOne_FormServiceImplTest";
private static final String NODE_FORM_ITEM_KIND = "node";
private static final String TYPE_FORM_ITEM_KIND = "type";
private static final String WORKFLOW_FORM_ITEM_KIND = "workflow";
/**
* Called during the transaction setup
@@ -122,6 +128,7 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
this.scriptService = (ScriptService)this.applicationContext.getBean("ScriptService");
this.personService = (PersonService)this.applicationContext.getBean("PersonService");
this.contentService = (ContentService)this.applicationContext.getBean("ContentService");
this.workflowService = (WorkflowService)this.applicationContext.getBean("WorkflowService");
AuthenticationComponent authenticationComponent = (AuthenticationComponent) this.applicationContext
.getBean("authenticationComponent");
@@ -1221,6 +1228,77 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
assertEquals(1, assocs.size());
}
public void testWorkflowForm() throws Exception
{
// generate a form for a well known workflow-definition supplying
// a legitimate set of fields for the workflow
List<String> fields = new ArrayList<String>(8);
fields.add("bpm:taskId");
fields.add("bpm:description");
fields.add("bpm:workflowDueDate");
//fields.add("packageItems");
String workflowDefName = "jbpm$wf:adhoc";
Form form = this.formService.getForm(new Item(WORKFLOW_FORM_ITEM_KIND, workflowDefName), fields);
// check a form got returned
assertNotNull("Expecting form to be present", form);
// check item identifier matches
assertEquals(WORKFLOW_FORM_ITEM_KIND, form.getItem().getKind());
assertEquals(workflowDefName, form.getItem().getId());
// check the field definitions
Collection<FieldDefinition> fieldDefs = form.getFieldDefinitions();
assertNotNull("Expecting to find fields", fieldDefs);
assertEquals("Expecting to find " + fields.size() + " fields", fields.size(), fieldDefs.size());
// check the fields are returned correctly
Map<String, FieldDefinition> fieldDefMap = new HashMap<String, FieldDefinition>(fieldDefs.size());
for (FieldDefinition fieldDef : fieldDefs)
{
fieldDefMap.put(fieldDef.getName(), fieldDef);
}
// find the fields
PropertyFieldDefinition idField = (PropertyFieldDefinition)fieldDefMap.get("bpm:taskId");
PropertyFieldDefinition descriptionField = (PropertyFieldDefinition)fieldDefMap.get("bpm:description");
PropertyFieldDefinition dueDateField = (PropertyFieldDefinition)fieldDefMap.get("bpm:workflowDueDate");
//AssociationFieldDefinition packageItemsField = (AssociationFieldDefinition)fieldDefMap.get("packageItems");
// check fields are present
assertNotNull("Expecting to find the bpm:taskId field", idField);
assertNotNull("Expecting to find the bpm:description field", descriptionField);
assertNotNull("Expecting to find the bpm:workflowDueDate field", dueDateField);
//assertNotNull("Expecting to find the packageItems field", packageItemsField);
// get the number of tasks now
List<WorkflowTask> tasks = this.workflowService.getAssignedTasks(USER_ONE,
WorkflowTaskState.IN_PROGRESS);
int tasksBefore = tasks.size();
// persist the form
FormData data = new FormData();
data.addFieldData("prop_bpm_description", "This is a new adhoc task");
data.addFieldData("assoc_bpm_assignee_added",
this.personService.getPerson(USER_ONE).toString());
//data.addFieldData("packageItems_added", this.document.toString());
// persist the data
WorkflowInstance workflow = (WorkflowInstance)this.formService.saveForm(
new Item(WORKFLOW_FORM_ITEM_KIND, workflowDefName), data);
// verify that the workflow was started by checking the user has one
// more task and the details on the workflow instance
tasks = this.workflowService.getAssignedTasks(USER_ONE,
WorkflowTaskState.IN_PROGRESS);
int tasksAfter = tasks.size();
assertTrue("Expecting there to be more tasks", tasksAfter > tasksBefore);
// check workflow instance details
assertEquals(workflowDefName, workflow.definition.name);
}
public void testNoForm() throws Exception
{
// test that a form can not be retrieved for a non-existent item

View File

@@ -18,8 +18,33 @@
*/
package org.alfresco.repo.forms.processor.workflow;
import org.alfresco.repo.forms.processor.node.TypeFormProcessor;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.forms.Form;
import org.alfresco.repo.forms.FormData;
import org.alfresco.repo.forms.FormNotFoundException;
import org.alfresco.repo.forms.Item;
import org.alfresco.repo.forms.processor.node.ContentModelFormProcessor;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.cmr.workflow.WorkflowInstance;
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.WorkflowTaskState;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Temporary FormProcessor implementation that can generate and persist
@@ -27,8 +52,12 @@ import org.alfresco.service.cmr.workflow.WorkflowService;
*
* @author Gavin Cornwell
*/
public class WorkflowFormProcessor extends TypeFormProcessor
public class WorkflowFormProcessor extends ContentModelFormProcessor<WorkflowDefinition, WorkflowInstance>
{
/** Logger */
private static Log logger = LogFactory.getLog(WorkflowFormProcessor.class);
/** workflow service */
protected WorkflowService workflowService;
/**
@@ -40,4 +69,207 @@ public class WorkflowFormProcessor extends TypeFormProcessor
{
this.workflowService = workflowService;
}
/*
* @see
* org.alfresco.repo.forms.processor.node.ContentModelFormProcessor#getLogger
* ()
*/
@Override
protected Log getLogger()
{
return logger;
}
/*
* @see
* org.alfresco.repo.forms.processor.node.NodeFormProcessor#getTypedItem
* (org.alfresco.repo.forms.Item)
*/
@Override
protected WorkflowDefinition getTypedItem(Item item)
{
WorkflowDefinition workflowDef = null;
try
{
// item id could be the raw workflow definition name or it could be
// in a URL friendly format
String workflowDefName = item.getId();
if (workflowDefName.indexOf("$") == -1)
{
// decode the itemId
workflowDefName = workflowDefName.replace("jbpm_", "jbpm$");
workflowDefName = workflowDefName.replace('_', ':');
}
// Extract the workflow definition
workflowDef = this.workflowService.getDefinitionByName(workflowDefName);
if (workflowDef == null)
{
throw new FormNotFoundException(item,
new IllegalArgumentException("Workflow definition does not exist: " + item.getId()));
}
}
catch (WorkflowException we)
{
throw new FormNotFoundException(item, we);
}
// return the type definition object for the requested type
return workflowDef;
}
/*
* @see
* org.alfresco.repo.forms.processor.FilteredFormProcessor#internalGenerate
* (java.lang.Object, java.util.List, java.util.List,
* org.alfresco.repo.forms.Form, java.util.Map)
*/
@Override
protected void internalGenerate(WorkflowDefinition workflowDef, List<String> fields,
List<String> forcedFields, Form form, Map<String, Object> context)
{
if (logger.isDebugEnabled()) logger.debug("Generating form for item: " + workflowDef);
// generate the form for the workflow definition
form.getItem().setType(workflowDef.name);
form.getItem().setUrl("/api/workflow-definition/" + workflowDef.id);
// get the type of the start task for the workflow definition
TypeDefinition typeDef = workflowDef.getStartTaskDefinition().metadata;
if (fields != null && fields.size() > 0)
{
generateSelectedFields(null, typeDef, fields, forcedFields, form);
}
else
{
// setup field definitions and data
generateAllPropertyFields(typeDef, form);
generateAllAssociationFields(typeDef, form);
}
if (logger.isDebugEnabled()) logger.debug("Generating form: " + form);
}
/**
* Sets up the field definitions for all the type's properties.
*
* @param typeDef The type being setup
* @param form The Form instance to populate
*/
protected void generateAllPropertyFields(TypeDefinition typeDef, Form form)
{
// iterate round the property defintions and setup field definition
Map<QName, PropertyDefinition> propDefs = typeDef.getProperties();
for (PropertyDefinition propDef : propDefs.values())
{
generatePropertyField(propDef, form, this.namespaceService);
}
// get all default aspects for the type and iterate round their
// property definitions too
List<AspectDefinition> aspects = typeDef.getDefaultAspects(true);
for (AspectDefinition aspect : aspects)
{
propDefs = aspect.getProperties();
for (PropertyDefinition propDef : propDefs.values())
{
generatePropertyField(propDef, form, this.namespaceService);
}
}
}
/**
* Sets up the field definitions for all the type's associations.
*
* @param typeDef The type being setup
* @param form The Form instance to populate
*/
protected void generateAllAssociationFields(TypeDefinition typeDef, Form form)
{
// iterate round the association defintions and setup field definition
Map<QName, AssociationDefinition> assocDefs = typeDef.getAssociations();
for (AssociationDefinition assocDef : assocDefs.values())
{
generateAssociationField(assocDef, form, this.namespaceService);
}
// get all default aspects for the type and iterate round their
// association definitions too
List<AspectDefinition> aspects = typeDef.getDefaultAspects(true);
for (AspectDefinition aspect : aspects)
{
assocDefs = aspect.getAssociations();
for (AssociationDefinition assocDef : assocDefs.values())
{
generateAssociationField(assocDef, form, this.namespaceService);
}
}
}
/*
* @see
* org.alfresco.repo.forms.processor.node.NodeFormProcessor#internalPersist
* (java.lang.Object, org.alfresco.repo.forms.FormData)
*/
@Override
protected WorkflowInstance internalPersist(WorkflowDefinition workflowDef, final FormData data)
{
if (logger.isDebugEnabled()) logger.debug("Persisting form for: " + workflowDef);
WorkflowInstance workflow = null;
Map<QName, Serializable> params = new HashMap<QName, Serializable>(8);
// create a package for the workflow
NodeRef workflowPackage = this.workflowService.createPackage(null);
params.put(WorkflowModel.ASSOC_PACKAGE, workflowPackage);
// TODO: iterate through form data to collect properties, for now
// just hardcode the ones we know
params.put(WorkflowModel.PROP_DESCRIPTION,
(Serializable)data.getFieldData("prop_bpm_description").getValue());
NodeRef assignee = new NodeRef(data.getFieldData("assoc_bpm_assignee_added").getValue().toString());
ArrayList<NodeRef> assigneeList = new ArrayList<NodeRef>(1);
assigneeList.add(assignee);
params.put(WorkflowModel.ASSOC_ASSIGNEE, assigneeList);
// TODO: add any package items
// TODO: add any context (this could re-use alf_destination)
// start the workflow to get access to the start task
WorkflowPath path = this.workflowService.startWorkflow(workflowDef.getId(), params);
if (path != null)
{
// get hold of the workflow instance for returning
workflow = path.instance;
// extract the start task
List<WorkflowTask> tasks = this.workflowService.getTasksForWorkflowPath(path.id);
if (tasks.size() == 1)
{
WorkflowTask startTask = tasks.get(0);
if (logger.isDebugEnabled())
logger.debug("Found start task:" + startTask);
if (startTask.state == WorkflowTaskState.IN_PROGRESS)
{
// end the start task to trigger the first 'proper'
// task in the workflow
this.workflowService.endTask(startTask.id, null);
}
}
if (logger.isDebugEnabled())
logger.debug("Started workflow: " + workflowDef.getId());
}
// return the workflow just started
return workflow;
}
}