mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Merge V1.4 to HEAD
- Ignored Enterprise-specific changes svn merge svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@3701 svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@3703 . svn merge svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@3704 svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@3705 . svn merge svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@3707 svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@3876 . svn revert root\projects\web-client\source\web\jsp\admin\admin-console.jsp git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3879 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -31,20 +31,24 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
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.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Simple workflow action executor
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
* @author David Caruana
|
||||
*/
|
||||
public class StartWorkflowActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
public static final String NAME = "start-workflow";
|
||||
|
||||
public static final String PARAM_WORKFLOW_NAME = "workflowName";
|
||||
public static final String PARAM_END_START_TASK = "endStartTask";
|
||||
public static final String PARAM_START_TASK_TRANSITION = "startTaskTransition";
|
||||
|
||||
|
||||
// action dependencies
|
||||
private NamespaceService namespaceService;
|
||||
@@ -94,7 +98,9 @@ public class StartWorkflowActionExecuter extends ActionExecuterAbstractBase
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_WORKFLOW_NAME, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_WORKFLOW_NAME)));
|
||||
// TODO: Start Task Template parameter
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_END_START_TASK, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_END_START_TASK)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_START_TASK_TRANSITION, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_START_TASK_TRANSITION)));
|
||||
// TODO: start task node parameter
|
||||
}
|
||||
|
||||
|
||||
@@ -127,9 +133,31 @@ public class StartWorkflowActionExecuter extends ActionExecuterAbstractBase
|
||||
workflowParameters.put(qname, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// provide a default context, if one is not specified
|
||||
Serializable context = workflowParameters.get(WorkflowModel.PROP_CONTEXT);
|
||||
if (context == null)
|
||||
{
|
||||
workflowParameters.put(WorkflowModel.PROP_CONTEXT, childAssoc.getParentRef());
|
||||
}
|
||||
|
||||
// start the workflow
|
||||
workflowService.startWorkflow(def.id, workflowParameters);
|
||||
WorkflowPath path = workflowService.startWorkflow(def.id, workflowParameters);
|
||||
|
||||
// determine whether to auto-end the start task
|
||||
Boolean endStartTask = (Boolean)ruleAction.getParameterValue(PARAM_END_START_TASK);
|
||||
String startTaskTransition = (String)ruleAction.getParameterValue(PARAM_START_TASK_TRANSITION);
|
||||
endStartTask = (endStartTask == null) ? true : false;
|
||||
startTaskTransition = (startTaskTransition == null) ? "" : startTaskTransition;
|
||||
|
||||
// auto-end the start task with the provided transition (if one)
|
||||
if (endStartTask)
|
||||
{
|
||||
List<WorkflowTask> tasks = workflowService.getTasksForWorkflowPath(path.id);
|
||||
for (WorkflowTask task : tasks)
|
||||
{
|
||||
workflowService.endTask(task.id, startTaskTransition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -31,9 +31,9 @@ import org.alfresco.util.BaseSpringTest;
|
||||
import org.alfresco.util.GUID;
|
||||
|
||||
/**
|
||||
* Add features action execution test
|
||||
* Start Advanced Workflow action execution test
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
* @author David Caruana
|
||||
*/
|
||||
public class StartWorkflowActionExecuterTest extends BaseSpringTest
|
||||
{
|
||||
@@ -78,9 +78,10 @@ public class StartWorkflowActionExecuterTest extends BaseSpringTest
|
||||
// Execute the action
|
||||
ActionImpl action = new ActionImpl(null, GUID.generate(), StartWorkflowActionExecuter.NAME, null);
|
||||
action.setParameterValue(StartWorkflowActionExecuter.PARAM_WORKFLOW_NAME, "jbpm$wf:review");
|
||||
action.setParameterValue(WorkflowModel.PROP_REVIEW_DUE_DATE.toPrefixString(namespaceService), new Date());
|
||||
action.setParameterValue(WorkflowModel.PROP_WORKFLOW_DUE_DATE.toPrefixString(namespaceService), new Date());
|
||||
NodeRef reviewer = personService.getPerson("admin");
|
||||
action.setParameterValue(WorkflowModel.ASSOC_REVIEWER.toPrefixString(namespaceService), reviewer);
|
||||
action.setParameterValue(WorkflowModel.ASSOC_ASSIGNEE.toPrefixString(namespaceService), reviewer);
|
||||
executer.execute(action, this.nodeRef);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -118,6 +118,14 @@ public interface WorkflowComponent
|
||||
*/
|
||||
public List<WorkflowInstance> getActiveWorkflows(String workflowDefinitionId);
|
||||
|
||||
/**
|
||||
* Gets a specific workflow instances
|
||||
*
|
||||
* @param workflowId the id of the workflow to retrieve
|
||||
* @return the workflow instance
|
||||
*/
|
||||
public WorkflowInstance getWorkflowById(String workflowId);
|
||||
|
||||
/**
|
||||
* Gets all Paths for the specified Workflow instance
|
||||
*
|
||||
|
@@ -16,12 +16,15 @@
|
||||
*/
|
||||
package org.alfresco.repo.workflow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.dictionary.DictionaryBootstrap;
|
||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.service.cmr.view.ImporterException;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDeployment;
|
||||
@@ -56,7 +59,10 @@ public class WorkflowDeployer implements ApplicationListener
|
||||
private TransactionService transactionService;
|
||||
private WorkflowService workflowService;
|
||||
private AuthenticationComponent authenticationComponent;
|
||||
private DictionaryDAO dictionaryDAO;
|
||||
private List<Properties> workflowDefinitions;
|
||||
private List<String> models = new ArrayList<String>();
|
||||
private List<String> resourceBundles = new ArrayList<String>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -89,6 +95,16 @@ public class WorkflowDeployer implements ApplicationListener
|
||||
this.authenticationComponent = authenticationComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Dictionary DAO
|
||||
*
|
||||
* @param dictionaryDAO
|
||||
*/
|
||||
public void setDictionaryDAO(DictionaryDAO dictionaryDAO)
|
||||
{
|
||||
this.dictionaryDAO = dictionaryDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Workflow Definitions
|
||||
*
|
||||
@@ -99,6 +115,26 @@ public class WorkflowDeployer implements ApplicationListener
|
||||
this.workflowDefinitions = workflowDefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial list of Workflow models to bootstrap with
|
||||
*
|
||||
* @param modelResources the model names
|
||||
*/
|
||||
public void setModels(List<String> modelResources)
|
||||
{
|
||||
this.models = modelResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial list of Workflow reosurce bundles to bootstrap with
|
||||
*
|
||||
* @param modelResources the model names
|
||||
*/
|
||||
public void setLabels(List<String> labels)
|
||||
{
|
||||
this.resourceBundles = labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy the Workflow Definitions
|
||||
*/
|
||||
@@ -124,6 +160,16 @@ public class WorkflowDeployer implements ApplicationListener
|
||||
{
|
||||
userTransaction.begin();
|
||||
|
||||
// bootstrap the workflow models and labels
|
||||
if (models != null && resourceBundles != null)
|
||||
{
|
||||
DictionaryBootstrap dictionaryBootstrap = new DictionaryBootstrap();
|
||||
dictionaryBootstrap.setDictionaryDAO(dictionaryDAO);
|
||||
dictionaryBootstrap.setModels(models);
|
||||
dictionaryBootstrap.setLabels(resourceBundles);
|
||||
dictionaryBootstrap.bootstrap();
|
||||
}
|
||||
|
||||
// bootstrap the workflow definitions
|
||||
if (workflowDefinitions != null)
|
||||
{
|
||||
|
@@ -45,26 +45,23 @@ public interface WorkflowModel
|
||||
// workflow task contstants
|
||||
static final QName TYPE_WORKFLOW_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowTask");
|
||||
static final QName PROP_CONTEXT = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "context");
|
||||
static final QName PROP_DESCRIPTION = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "description");
|
||||
static final QName PROP_OUTCOME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "outcome");
|
||||
static final QName PROP_PACKAGE_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageActionGroup");
|
||||
static final QName PROP_PACKAGE_ITEM_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageItemActionGroup");
|
||||
static final QName ASSOC_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "package");
|
||||
|
||||
|
||||
// workflow task contstants
|
||||
static final QName TYPE_START_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "startTask");
|
||||
static final QName PROP_WORKFLOW_DESCRIPTION = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDescription");
|
||||
static final QName PROP_WORKFLOW_PRIORITY = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowPriority");
|
||||
static final QName PROP_WORKFLOW_DUE_DATE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDueDate");
|
||||
static final QName ASSOC_ASSIGNEE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "assignee");
|
||||
|
||||
// workflow package
|
||||
static final QName ASPECT_WORKFLOW_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowPackage");
|
||||
static final QName PROP_WORKFLOW_DEFINITION_ID = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDefinitionId");
|
||||
static final QName PROP_WORKFLOW_DEFINITION_NAME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDefinitionName");
|
||||
static final QName PROP_WORKFLOW_INSTANCE_ID = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowInstanceId");
|
||||
|
||||
|
||||
//
|
||||
// Workflow Models
|
||||
//
|
||||
|
||||
// review & approve
|
||||
static final QName TYPE_SUBMITREVIEW_TASK = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "submitReviewTask");
|
||||
static final QName PROP_REVIEW_PRIORITY = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "reviewPriority");
|
||||
static final QName PROP_REVIEW_DUE_DATE = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "reviewDueDate");
|
||||
static final QName ASSOC_REVIEWER = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "reviewer");
|
||||
|
||||
|
||||
}
|
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package org.alfresco.repo.workflow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
|
||||
@@ -38,6 +40,14 @@ public interface WorkflowPackageComponent
|
||||
*/
|
||||
public NodeRef createPackage(NodeRef container);
|
||||
|
||||
// TODO: Support for finding packages via meta-data of WorkflowPackage aspect
|
||||
// TODO: Further support for finding packages via meta-data of WorkflowPackage aspect
|
||||
|
||||
/**
|
||||
* Gets the Workflows that act upon the specified Repository content.
|
||||
*
|
||||
* @param packageItem the repository content item to get workflows for
|
||||
* @return list of workflows which act upon the specified content
|
||||
*/
|
||||
public List<String> getWorkflowIdsForContent(NodeRef packageItem);
|
||||
|
||||
}
|
||||
|
@@ -21,8 +21,6 @@ import java.util.List;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.importer.ImporterBootstrap;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
@@ -31,6 +29,7 @@ import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
|
||||
/**
|
||||
@@ -41,14 +40,13 @@ import org.alfresco.util.GUID;
|
||||
*/
|
||||
public class WorkflowPackageImpl implements WorkflowPackageComponent
|
||||
{
|
||||
private final static String PACKAGE_FOLDER = "Workflow Packages";
|
||||
private final static String PACKAGE_FOLDER = "packages";
|
||||
|
||||
// service dependencies
|
||||
private ImporterBootstrap bootstrap;
|
||||
private SearchService searchService;
|
||||
private NodeService nodeService;
|
||||
private NamespaceService namespaceService;
|
||||
private FileFolderService fileFolderService;
|
||||
private NodeRef systemWorkflowContainer = null;
|
||||
|
||||
|
||||
@@ -60,14 +58,6 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent
|
||||
this.bootstrap = bootstrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileFolderService file folder service
|
||||
*/
|
||||
public void setFileFolderService(FileFolderService fileFolderService)
|
||||
{
|
||||
this.fileFolderService = fileFolderService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchService search service
|
||||
*/
|
||||
@@ -105,11 +95,23 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent
|
||||
NodeRef system = getSystemWorkflowContainer();
|
||||
|
||||
// TODO: Consider structuring this folder, if number of children becomes an issue
|
||||
List<String> folders = new ArrayList<String>();
|
||||
folders.add(PACKAGE_FOLDER);
|
||||
folders.add(GUID.generate());
|
||||
FileInfo containerFolder = fileFolderService.makeFolders(system, folders, ContentModel.TYPE_FOLDER);
|
||||
container = containerFolder.getNodeRef();
|
||||
NodeRef packages = null;
|
||||
List<NodeRef> results = searchService.selectNodes(system, "./" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + PACKAGE_FOLDER, null, namespaceService, false);
|
||||
if (results.size() > 0)
|
||||
{
|
||||
packages = results.get(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
QName qname = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, PACKAGE_FOLDER);
|
||||
ChildAssociationRef childRef = nodeService.createNode(system, ContentModel.ASSOC_CHILDREN, qname, ContentModel.TYPE_SYSTEM_FOLDER);
|
||||
packages = childRef.getChildRef();
|
||||
}
|
||||
|
||||
String containerName = "pkg_" + GUID.generate();
|
||||
QName qname = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, containerName);
|
||||
ChildAssociationRef childRef = nodeService.createNode(packages, ContentModel.ASSOC_CONTAINS, qname, ContentModel.TYPE_SYSTEM_FOLDER);
|
||||
container = childRef.getChildRef();
|
||||
}
|
||||
|
||||
// attach workflow package
|
||||
@@ -123,6 +125,32 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent
|
||||
return container;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowPackageComponent#getWorkflowIdsForContent(org.alfresco.service.cmr.repository.NodeRef, boolean)
|
||||
*/
|
||||
public List<String> getWorkflowIdsForContent(NodeRef packageItem)
|
||||
{
|
||||
ParameterCheck.mandatory("packageItem", packageItem);
|
||||
List<String> workflowIds = new ArrayList<String>();
|
||||
if (nodeService.exists(packageItem))
|
||||
{
|
||||
List<ChildAssociationRef> packageItemParents = nodeService.getParentAssocs(packageItem);
|
||||
for (ChildAssociationRef packageItemParent : packageItemParents)
|
||||
{
|
||||
NodeRef parentRef = packageItemParent.getParentRef();
|
||||
if (nodeService.hasAspect(parentRef, WorkflowModel.ASPECT_WORKFLOW_PACKAGE))
|
||||
{
|
||||
String workflowInstance = (String)nodeService.getProperty(parentRef, WorkflowModel.PROP_WORKFLOW_INSTANCE_ID);
|
||||
if (workflowInstance != null && workflowInstance.length() > 0)
|
||||
{
|
||||
workflowIds.add(workflowInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return workflowIds;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the system workflow container for storing workflow related items
|
||||
@@ -201,10 +229,10 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent
|
||||
{
|
||||
String name = bootstrap.getConfiguration().getProperty("system.workflow_container.childname");
|
||||
QName qname = QName.createQName(name, namespaceService);
|
||||
ChildAssociationRef childRef = nodeService.createNode(systemContainer, ContentModel.ASSOC_CHILDREN, qname, ContentModel.TYPE_FOLDER);
|
||||
ChildAssociationRef childRef = nodeService.createNode(systemContainer, ContentModel.ASSOC_CHILDREN, qname, ContentModel.TYPE_CONTAINER);
|
||||
systemWorkflowContainer = childRef.getChildRef();
|
||||
}
|
||||
return systemWorkflowContainer;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -185,6 +185,16 @@ public class WorkflowServiceImpl implements WorkflowService
|
||||
return component.getActiveWorkflows(workflowDefinitionId);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getWorkflowById(java.lang.String)
|
||||
*/
|
||||
public WorkflowInstance getWorkflowById(String workflowId)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(workflowId);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
return component.getWorkflowById(workflowId);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getWorkflowPaths(java.lang.String)
|
||||
*/
|
||||
@@ -296,6 +306,27 @@ public class WorkflowServiceImpl implements WorkflowService
|
||||
{
|
||||
return workflowPackageComponent.createPackage(container);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getWorkflowsForContent(org.alfresco.service.cmr.repository.NodeRef, boolean)
|
||||
*/
|
||||
public List<WorkflowInstance> getWorkflowsForContent(NodeRef packageItem, boolean active)
|
||||
{
|
||||
List<String> workflowIds = workflowPackageComponent.getWorkflowIdsForContent(packageItem);
|
||||
List<WorkflowInstance> workflowInstances = new ArrayList<WorkflowInstance>(workflowIds.size());
|
||||
for (String workflowId : workflowIds)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(workflowId);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
WorkflowInstance instance = component.getWorkflowById(workflowId);
|
||||
if (instance.active == active)
|
||||
{
|
||||
workflowInstances.add(instance);
|
||||
}
|
||||
}
|
||||
return workflowInstances;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the Workflow Component registered against the specified BPM Engine Id
|
||||
|
@@ -16,15 +16,24 @@
|
||||
*/
|
||||
package org.alfresco.repo.workflow;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
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.workflow.WorkflowDefinition;
|
||||
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.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
|
||||
|
||||
@@ -43,7 +52,7 @@ public class WorkflowServiceImplTest extends BaseSpringTest
|
||||
{
|
||||
workflowService = (WorkflowService)applicationContext.getBean(ServiceRegistry.WORKFLOW_SERVICE.getLocalName());
|
||||
nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName());
|
||||
|
||||
|
||||
// authenticate
|
||||
AuthenticationComponent auth = (AuthenticationComponent) applicationContext.getBean("authenticationComponent");
|
||||
auth.setSystemUserAsCurrentUser();
|
||||
@@ -77,4 +86,44 @@ public class WorkflowServiceImplTest extends BaseSpringTest
|
||||
assertTrue(nodeService.hasAspect(nodeRef, WorkflowModel.ASPECT_WORKFLOW_PACKAGE));
|
||||
}
|
||||
|
||||
public void testAssociateWorkflowPackage()
|
||||
{
|
||||
// create workflow package
|
||||
NodeRef rootRef = nodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "spacesStore"));
|
||||
NodeRef nodeRef = workflowService.createPackage(null);
|
||||
assertNotNull(nodeRef);
|
||||
assertTrue(nodeService.hasAspect(nodeRef, WorkflowModel.ASPECT_WORKFLOW_PACKAGE));
|
||||
ChildAssociationRef childAssoc = nodeService.createNode(rootRef, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_PREFIX, "test"), ContentModel.TYPE_CONTENT, null);
|
||||
nodeService.addChild(nodeRef, childAssoc.getChildRef(), ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_PREFIX, "test"));
|
||||
|
||||
// start workflow
|
||||
List<WorkflowDefinition> workflowDefs = workflowService.getDefinitions();
|
||||
assertNotNull(workflowDefs);
|
||||
assertTrue(workflowDefs.size() > 0);
|
||||
WorkflowDefinition workflowDef = workflowDefs.get(0);
|
||||
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
||||
parameters.put(WorkflowModel.ASSOC_PACKAGE, nodeRef);
|
||||
WorkflowPath path = workflowService.startWorkflow(workflowDef.id, parameters);
|
||||
assertNotNull(path);
|
||||
assertTrue(path.active);
|
||||
assertNotNull(path.node);
|
||||
assertNotNull(path.instance);
|
||||
assertEquals(workflowDef.id, path.instance.definition.id);
|
||||
String workflowDefId = (String)nodeService.getProperty(nodeRef, WorkflowModel.PROP_WORKFLOW_DEFINITION_ID);
|
||||
assertEquals(workflowDefId, workflowDef.id);
|
||||
String workflowDefName = (String)nodeService.getProperty(nodeRef, WorkflowModel.PROP_WORKFLOW_DEFINITION_NAME);
|
||||
assertEquals(workflowDefName, workflowDef.name);
|
||||
String workflowInstanceId = (String)nodeService.getProperty(nodeRef, WorkflowModel.PROP_WORKFLOW_INSTANCE_ID);
|
||||
assertEquals(workflowInstanceId, path.instance.id);
|
||||
|
||||
// get workflows for content
|
||||
List<WorkflowInstance> instances = workflowService.getWorkflowsForContent(childAssoc.getChildRef(), true);
|
||||
assertNotNull(instances);
|
||||
assertEquals(1, instances.size());
|
||||
assertEquals(instances.get(0).id, path.instance.id);
|
||||
List<WorkflowInstance> completedInstances = workflowService.getWorkflowsForContent(childAssoc.getChildRef(), false);
|
||||
assertNotNull(completedInstances);
|
||||
assertEquals(0, completedInstances.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ import java.util.Map;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ScriptService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
import org.dom4j.Element;
|
||||
import org.jbpm.context.def.VariableAccess;
|
||||
import org.jbpm.context.exe.ContextInstance;
|
||||
@@ -36,7 +37,7 @@ import org.xml.sax.InputSource;
|
||||
* A jBPM Action Handler for executing Alfresco Script
|
||||
*
|
||||
* The configuration of this action is as follows:
|
||||
* <script language="javascript">
|
||||
* <script>
|
||||
* <expression>
|
||||
* the script to execute
|
||||
* </expression>
|
||||
@@ -72,6 +73,12 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute(ExecutionContext executionContext) throws Exception
|
||||
{
|
||||
// validate script
|
||||
if (script == null)
|
||||
{
|
||||
throw new WorkflowException("Script has not been provided");
|
||||
}
|
||||
|
||||
// extract action configuration
|
||||
String expression = null;
|
||||
List<VariableAccess> variableAccesses = null;
|
||||
@@ -96,7 +103,12 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
||||
else
|
||||
{
|
||||
variableAccesses = jpdlReader.readVariableAccesses(script);
|
||||
expression = script.element("expression").getTextTrim();
|
||||
Element expressionElement = script.element("expression");
|
||||
if (expressionElement == null)
|
||||
{
|
||||
throw new WorkflowException("Script expression has not been provided");
|
||||
}
|
||||
expression = expressionElement.getTextTrim();
|
||||
}
|
||||
|
||||
// construct script arguments and execute
|
||||
|
@@ -67,6 +67,7 @@ import org.hibernate.proxy.HibernateProxy;
|
||||
import org.jbpm.JbpmContext;
|
||||
import org.jbpm.JbpmException;
|
||||
import org.jbpm.context.exe.ContextInstance;
|
||||
import org.jbpm.context.exe.TokenVariableMap;
|
||||
import org.jbpm.db.GraphSession;
|
||||
import org.jbpm.db.TaskMgmtSession;
|
||||
import org.jbpm.graph.def.Node;
|
||||
@@ -432,6 +433,30 @@ public class JBPMEngine extends BPMEngine
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowComponent#getWorkflowById(java.lang.String)
|
||||
*/
|
||||
public WorkflowInstance getWorkflowById(final String workflowId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (WorkflowInstance) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public Object doInJbpm(JbpmContext context)
|
||||
{
|
||||
// retrieve workflow
|
||||
GraphSession graphSession = context.getGraphSession();
|
||||
ProcessInstance processInstance = graphSession.getProcessInstance(getJbpmId(workflowId));
|
||||
return createWorkflowInstance(processInstance);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to retrieve workflow instance '" + workflowId + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowComponent#getWorkflowPaths(java.lang.String)
|
||||
*/
|
||||
@@ -479,16 +504,48 @@ public class JBPMEngine extends BPMEngine
|
||||
{
|
||||
return (WorkflowInstance) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object doInJbpm(JbpmContext context)
|
||||
{
|
||||
// retrieve and cancel process instance
|
||||
GraphSession graphSession = context.getGraphSession();
|
||||
ProcessInstance processInstance = graphSession.loadProcessInstance(getJbpmId(workflowId));
|
||||
processInstance.end();
|
||||
// TODO: Determine if this is the most appropriate way to cancel workflow...
|
||||
// It might be useful to record point at which it was cancelled etc
|
||||
WorkflowInstance workflowInstance = createWorkflowInstance(processInstance);
|
||||
|
||||
// save the process instance along with the task instance
|
||||
context.save(processInstance);
|
||||
return createWorkflowInstance(processInstance);
|
||||
//
|
||||
// TODO: remove - workaround for JBPM variable mapping constraint exception
|
||||
//
|
||||
Collection<TaskInstance> tasks = processInstance.getTaskMgmtInstance().getTaskInstances();
|
||||
for (TaskInstance task : tasks)
|
||||
{
|
||||
Map<String, Serializable> taskVariables = task.getVariablesLocally();
|
||||
for (String varName : taskVariables.keySet())
|
||||
{
|
||||
task.deleteVariableLocally(varName);
|
||||
}
|
||||
}
|
||||
ContextInstance processContext = processInstance.getContextInstance();
|
||||
Map<Token, TokenVariableMap> tokenVarMaps = processContext.getTokenVariableMaps();
|
||||
for (Map.Entry<Token, TokenVariableMap> mapEntry : tokenVarMaps.entrySet())
|
||||
{
|
||||
TokenVariableMap tokenVarMap = mapEntry.getValue();
|
||||
Map<String, Serializable> variables = tokenVarMap.getVariables();
|
||||
for (String name : variables.keySet())
|
||||
{
|
||||
tokenVarMap.deleteVariable(name);
|
||||
}
|
||||
}
|
||||
//
|
||||
// end TODO
|
||||
//
|
||||
|
||||
// delete the process instance
|
||||
graphSession.deleteProcessInstance(processInstance, true, true, true);
|
||||
workflowInstance.active = false;
|
||||
workflowInstance.endDate = new Date();
|
||||
return workflowInstance;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -705,7 +762,7 @@ public class JBPMEngine extends BPMEngine
|
||||
|
||||
if (add != null || remove != null)
|
||||
{
|
||||
Map<QName, Serializable> existingProperties = getTaskProperties(taskInstance);
|
||||
Map<QName, Serializable> existingProperties = getTaskProperties(taskInstance, false);
|
||||
|
||||
if (add != null)
|
||||
{
|
||||
@@ -815,6 +872,11 @@ public class JBPMEngine extends BPMEngine
|
||||
// retrieve task
|
||||
TaskMgmtSession taskSession = context.getTaskMgmtSession();
|
||||
TaskInstance taskInstance = taskSession.loadTaskInstance(getJbpmId(taskId));
|
||||
|
||||
// set status to complete
|
||||
Map<QName, Serializable> taskProperties = new HashMap<QName, Serializable>();
|
||||
taskProperties.put(WorkflowModel.PROP_STATUS, "Completed");
|
||||
setTaskProperties(taskInstance, taskProperties);
|
||||
|
||||
// signal the transition on the task
|
||||
if (transition == null)
|
||||
@@ -992,7 +1054,7 @@ public class JBPMEngine extends BPMEngine
|
||||
TypeDefinition typeDef = dictionaryService.getType(typeName);
|
||||
if (typeDef == null)
|
||||
{
|
||||
typeDef = dictionaryService.getType(WorkflowModel.TYPE_WORKFLOW_TASK);
|
||||
typeDef = dictionaryService.getType(task.getStartState() == null ? WorkflowModel.TYPE_WORKFLOW_TASK : WorkflowModel.TYPE_START_TASK);
|
||||
if (typeDef == null)
|
||||
{
|
||||
throw new WorkflowException("Failed to find type definition '" + WorkflowModel.TYPE_WORKFLOW_TASK + "'");
|
||||
@@ -1090,43 +1152,56 @@ public class JBPMEngine extends BPMEngine
|
||||
* @param properties properties to set
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Map<QName, Serializable> getTaskProperties(TaskInstance instance)
|
||||
protected Map<QName, Serializable> getTaskProperties(TaskInstance instance, boolean localProperties)
|
||||
{
|
||||
// retrieve type definition for task
|
||||
TypeDefinition taskDef = getAnonymousTaskDefinition(getTaskDefinition(instance.getTask()));
|
||||
Map<QName, PropertyDefinition> taskProperties = taskDef.getProperties();
|
||||
Map<QName, AssociationDefinition> taskAssocs = taskDef.getAssociations();
|
||||
|
||||
// map arbitrary task variables
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(10);
|
||||
Map<String, Object> vars = instance.getVariablesLocally();
|
||||
Map<String, Object> vars = (localProperties ? instance.getVariablesLocally() : instance.getVariables());
|
||||
|
||||
for (Entry<String, Object> entry : vars.entrySet())
|
||||
{
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
String name = key.replace("_", ":");
|
||||
QName qname = QName.createQName(name, this.namespaceService);
|
||||
|
||||
//
|
||||
// perform data conversions
|
||||
//
|
||||
|
||||
// Convert Nodes to NodeRefs
|
||||
if (value instanceof JBPMNode)
|
||||
// add variable, only if part of task definition or locally defined on task
|
||||
if (taskProperties.containsKey(qname) || taskAssocs.containsKey(qname) || instance.hasVariableLocally(key))
|
||||
{
|
||||
value = ((JBPMNode)value).getNodeRef();
|
||||
Object value = entry.getValue();
|
||||
|
||||
//
|
||||
// perform data conversions
|
||||
//
|
||||
|
||||
// Convert Nodes to NodeRefs
|
||||
if (value instanceof JBPMNode)
|
||||
{
|
||||
value = ((JBPMNode)value).getNodeRef();
|
||||
}
|
||||
else if (value instanceof JBPMNodeList)
|
||||
{
|
||||
JBPMNodeList nodes = (JBPMNodeList)value;
|
||||
List<NodeRef> nodeRefs = new ArrayList<NodeRef>(nodes.size());
|
||||
for (JBPMNode node : nodes)
|
||||
{
|
||||
nodeRefs.add(node.getNodeRef());
|
||||
}
|
||||
value = (Serializable)nodeRefs;
|
||||
}
|
||||
|
||||
// place task variable in map to return
|
||||
properties.put(qname, (Serializable)value);
|
||||
}
|
||||
else if (value instanceof JBPMNodeList)
|
||||
{
|
||||
JBPMNodeList nodes = (JBPMNodeList)value;
|
||||
List<NodeRef> nodeRefs = new ArrayList<NodeRef>(nodes.size());
|
||||
for (JBPMNode node : nodes)
|
||||
{
|
||||
nodeRefs.add(node.getNodeRef());
|
||||
}
|
||||
value = (Serializable)nodeRefs;
|
||||
}
|
||||
|
||||
// place task variable in map to return
|
||||
QName qname = QName.createQName(key, this.namespaceService);
|
||||
properties.put(qname, (Serializable)value);
|
||||
}
|
||||
|
||||
// map jBPM task instance fields to properties
|
||||
properties.put(WorkflowModel.PROP_TASK_ID, instance.getId());
|
||||
properties.put(WorkflowModel.PROP_DESCRIPTION, instance.getDescription());
|
||||
properties.put(WorkflowModel.PROP_START_DATE, instance.getStart());
|
||||
properties.put(WorkflowModel.PROP_DUE_DATE, instance.getDueDate());
|
||||
properties.put(WorkflowModel.PROP_COMPLETION_DATE, instance.getEnd());
|
||||
@@ -1207,6 +1282,15 @@ public class JBPMEngine extends BPMEngine
|
||||
}
|
||||
|
||||
// map property to specific jBPM task instance field
|
||||
if (key.equals(WorkflowModel.PROP_DESCRIPTION))
|
||||
{
|
||||
if (value != null && !(value instanceof String))
|
||||
{
|
||||
throw new WorkflowException("Task description '" + value + "' is invalid");
|
||||
}
|
||||
instance.setDescription((String)value);
|
||||
continue;
|
||||
}
|
||||
if (key.equals(WorkflowModel.PROP_DUE_DATE))
|
||||
{
|
||||
if (value != null && !(value instanceof Date))
|
||||
@@ -1269,6 +1353,40 @@ public class JBPMEngine extends BPMEngine
|
||||
instance.setPooledActors(pooledActors);
|
||||
continue;
|
||||
}
|
||||
else if (key.equals(WorkflowModel.ASSOC_PACKAGE))
|
||||
{
|
||||
// Attach workflow definition & instance id to Workflow Package in Repository
|
||||
String name = key.toPrefixString(this.namespaceService);
|
||||
name = name.replace(':', '_');
|
||||
JBPMNode existingWorkflowPackage = (JBPMNode)instance.getVariable(name);
|
||||
|
||||
// first check if provided workflow package has already been associated with another workflow instance
|
||||
if (existingWorkflowPackage != null && value != null)
|
||||
{
|
||||
NodeRef newPackageNodeRef = ((JBPMNode)value).getNodeRef();
|
||||
ProcessInstance processInstance = instance.getToken().getProcessInstance();
|
||||
String packageInstanceId = (String)nodeService.getProperty(newPackageNodeRef, WorkflowModel.PROP_WORKFLOW_INSTANCE_ID);
|
||||
if (packageInstanceId != null && packageInstanceId.length() > 0 && (processInstance.getId() == getJbpmId(packageInstanceId)))
|
||||
{
|
||||
String workflowInstanceId = createGlobalId(new Long(processInstance.getId()).toString());
|
||||
throw new WorkflowException("Cannot associate workflow package '" + newPackageNodeRef + "' with workflow instance '" + workflowInstanceId + "' as it's already associated with workflow instance '" + packageInstanceId + "'");
|
||||
}
|
||||
}
|
||||
|
||||
// initialise workflow package
|
||||
if (existingWorkflowPackage == null && value != null)
|
||||
{
|
||||
// initialise workflow package
|
||||
NodeRef newPackageNodeRef = ((JBPMNode)value).getNodeRef();
|
||||
ProcessInstance processInstance = instance.getToken().getProcessInstance();
|
||||
WorkflowInstance workflowInstance = createWorkflowInstance(processInstance);
|
||||
nodeService.setProperty(newPackageNodeRef, WorkflowModel.PROP_WORKFLOW_DEFINITION_ID, workflowInstance.definition.id);
|
||||
nodeService.setProperty(newPackageNodeRef, WorkflowModel.PROP_WORKFLOW_DEFINITION_NAME, workflowInstance.definition.name);
|
||||
nodeService.setProperty(newPackageNodeRef, WorkflowModel.PROP_WORKFLOW_INSTANCE_ID, workflowInstance.id);
|
||||
}
|
||||
|
||||
// NOTE: Fall-through to allow setting of Workflow Package on Task Instance
|
||||
}
|
||||
}
|
||||
|
||||
// untyped value, perform minimal conversion
|
||||
@@ -1284,6 +1402,7 @@ public class JBPMEngine extends BPMEngine
|
||||
// no specific mapping to jBPM task has been established, so place into
|
||||
// the generic task variable bag
|
||||
String name = key.toPrefixString(this.namespaceService);
|
||||
name = name.replace(':', '_');
|
||||
instance.setVariableLocally(name, value);
|
||||
}
|
||||
}
|
||||
@@ -1310,7 +1429,7 @@ public class JBPMEngine extends BPMEngine
|
||||
{
|
||||
if (existingValues == null)
|
||||
{
|
||||
existingValues = getTaskProperties(instance);
|
||||
existingValues = getTaskProperties(instance, true);
|
||||
}
|
||||
if (existingValues.get(entry.getKey()) == null)
|
||||
{
|
||||
@@ -1319,6 +1438,22 @@ public class JBPMEngine extends BPMEngine
|
||||
}
|
||||
}
|
||||
|
||||
// special case for task description default value
|
||||
String description = (String)existingValues.get(WorkflowModel.PROP_DESCRIPTION);
|
||||
if (description == null || description.length() == 0)
|
||||
{
|
||||
description = (String)instance.getContextInstance().getVariable("bpm_workflowDescription");
|
||||
if (description != null && description.length() > 0)
|
||||
{
|
||||
defaultValues.put(WorkflowModel.PROP_DESCRIPTION, description);
|
||||
}
|
||||
else
|
||||
{
|
||||
WorkflowTask task = createWorkflowTask(instance);
|
||||
defaultValues.put(WorkflowModel.PROP_DESCRIPTION, task.title);
|
||||
}
|
||||
}
|
||||
|
||||
// assign the default values to the task
|
||||
if (defaultValues.size() > 0)
|
||||
{
|
||||
@@ -1566,7 +1701,7 @@ public class JBPMEngine extends BPMEngine
|
||||
workflowTask.path = createWorkflowPath(task.getToken());
|
||||
workflowTask.state = getWorkflowTaskState(task);
|
||||
workflowTask.definition = createWorkflowTaskDefinition(task.getTask());
|
||||
workflowTask.properties = getTaskProperties(task);
|
||||
workflowTask.properties = getTaskProperties(task, false);
|
||||
workflowTask.title = getLabel(processName + ".task." + workflowTask.name, TITLE_LABEL, null);
|
||||
if (workflowTask.title == null)
|
||||
{
|
||||
|
@@ -152,6 +152,21 @@ public class JBPMEngineTest extends BaseSpringTest
|
||||
}
|
||||
|
||||
|
||||
public void testGetWorkflowInstance()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, null);
|
||||
assertNotNull(path);
|
||||
assertTrue(path.id.endsWith("-@"));
|
||||
assertNotNull(path.node);
|
||||
assertNotNull(path.instance);
|
||||
assertEquals(workflowDef.id, path.instance.definition.id);
|
||||
WorkflowInstance instance = workflowComponent.getWorkflowById(path.instance.id);
|
||||
assertNotNull(instance);
|
||||
assertEquals(path.instance.id, instance.id);
|
||||
}
|
||||
|
||||
|
||||
public void testStartWorkflowParameters()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
@@ -303,20 +318,27 @@ public class JBPMEngineTest extends BaseSpringTest
|
||||
|
||||
public void testCancelWorkflowInstance()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
workflowComponent.startWorkflow(workflowDef.id, null);
|
||||
List<WorkflowInstance> instances1 = workflowComponent.getActiveWorkflows(workflowDef.id);
|
||||
assertNotNull(instances1);
|
||||
assertEquals(1, instances1.size());
|
||||
List<WorkflowTask> tasks = taskComponent.getAssignedTasks("admin", WorkflowTaskState.IN_PROGRESS);
|
||||
assertNotNull(tasks);
|
||||
assertTrue(tasks.size() > 0);
|
||||
WorkflowInstance cancelledInstance = workflowComponent.cancelWorkflow(instances1.get(0).id);
|
||||
assertNotNull(cancelledInstance);
|
||||
assertFalse(cancelledInstance.active);
|
||||
List<WorkflowInstance> instances2 = workflowComponent.getActiveWorkflows(workflowDef.id);
|
||||
assertNotNull(instances2);
|
||||
assertEquals(0, instances2.size());
|
||||
List<WorkflowTask> tasks1 = taskComponent.getAssignedTasks("admin", WorkflowTaskState.IN_PROGRESS);
|
||||
assertNotNull(tasks1);
|
||||
tasks1 = filterTasksByWorkflowInstance(tasks1, cancelledInstance.id);
|
||||
assertEquals(0, tasks1.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testSignal()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
@@ -335,7 +357,6 @@ public class JBPMEngineTest extends BaseSpringTest
|
||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "testNode"), testNodeRef);
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
||||
assertNotNull(path);
|
||||
assertNotNull(path);
|
||||
List<WorkflowTask> tasks = workflowComponent.getTasksForWorkflowPath(path.id);
|
||||
assertNotNull(tasks);
|
||||
assertEquals(1, tasks.size());
|
||||
@@ -361,7 +382,6 @@ public class JBPMEngineTest extends BaseSpringTest
|
||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "testNode"), testNodeRef);
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
||||
assertNotNull(path);
|
||||
assertNotNull(path);
|
||||
List<WorkflowTask> tasks1 = workflowComponent.getTasksForWorkflowPath(path.id);
|
||||
assertNotNull(tasks1);
|
||||
assertEquals(1, tasks1.size());
|
||||
|
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.workflow.jbpm;
|
||||
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.transaction.TransactionListener;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jbpm.JbpmConfiguration;
|
||||
import org.jbpm.JbpmContext;
|
||||
import org.jbpm.graph.def.ProcessDefinition;
|
||||
import org.springmodules.workflow.jbpm31.JbpmTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* JBPM Template that manages JBPM Context at the Alfresco Transaction level
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class JBPMTransactionTemplate extends JbpmTemplate
|
||||
implements TransactionListener
|
||||
{
|
||||
// Logging support
|
||||
private static Log logger = LogFactory.getLog("org.alfresco.repo.workflow");
|
||||
|
||||
/** Id used in equals and hash */
|
||||
private String id = GUID.generate();
|
||||
|
||||
// JBPM Template Keys
|
||||
private static final String JBPM_CONTEXT_KEY = JBPMTransactionTemplate.class.getName() + ".context";
|
||||
|
||||
/** Use local or transaction bound JBPM Context */
|
||||
private boolean localContext = true;
|
||||
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public JBPMTransactionTemplate()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public JBPMTransactionTemplate(JbpmConfiguration jbpmConfiguration, ProcessDefinition processDefinition)
|
||||
{
|
||||
super(jbpmConfiguration, processDefinition);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public JBPMTransactionTemplate(JbpmConfiguration jbpmConfiguration)
|
||||
{
|
||||
super(jbpmConfiguration);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
JBPMTransactionTemplate.super.afterPropertiesSet();
|
||||
}
|
||||
finally
|
||||
{
|
||||
localContext = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springmodules.workflow.jbpm31.JbpmTemplate#getContext()
|
||||
*/
|
||||
@Override
|
||||
protected JbpmContext getContext()
|
||||
{
|
||||
if (localContext)
|
||||
{
|
||||
return super.getContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
JbpmContext context = (JbpmContext)AlfrescoTransactionSupport.getResource(JBPM_CONTEXT_KEY);
|
||||
if (context == null)
|
||||
{
|
||||
context = super.getContext();
|
||||
AlfrescoTransactionSupport.bindResource(JBPM_CONTEXT_KEY, context);
|
||||
AlfrescoTransactionSupport.bindListener(this);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Attached JBPM Context to transaction " + AlfrescoTransactionSupport.getTransactionId());
|
||||
}
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springmodules.workflow.jbpm31.JbpmTemplate#releaseContext(org.jbpm.JbpmContext)
|
||||
*/
|
||||
@Override
|
||||
protected void releaseContext(JbpmContext jbpmContext)
|
||||
{
|
||||
if (localContext)
|
||||
{
|
||||
jbpmContext.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: Defer release to end of transaction
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#flush()
|
||||
*/
|
||||
public void flush()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#beforeCommit(boolean)
|
||||
*/
|
||||
public void beforeCommit(boolean readOnly)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#beforeCompletion()
|
||||
*/
|
||||
public void beforeCompletion()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#afterCommit()
|
||||
*/
|
||||
public void afterCommit()
|
||||
{
|
||||
JbpmContext context = (JbpmContext)AlfrescoTransactionSupport.getResource(JBPM_CONTEXT_KEY);
|
||||
if (context != null)
|
||||
{
|
||||
super.releaseContext(context);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Detached (commit) JBPM Context from transaction " + AlfrescoTransactionSupport.getTransactionId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#afterRollback()
|
||||
*/
|
||||
public void afterRollback()
|
||||
{
|
||||
JbpmContext context = (JbpmContext)AlfrescoTransactionSupport.getResource(JBPM_CONTEXT_KEY);
|
||||
if (context != null)
|
||||
{
|
||||
super.releaseContext(context);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Detached (rollback) JBPM Context from transaction " + AlfrescoTransactionSupport.getTransactionId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return this.id.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof JBPMTransactionTemplate)
|
||||
{
|
||||
JBPMTransactionTemplate that = (JBPMTransactionTemplate) obj;
|
||||
return (this.id.equals(that.id));
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -69,7 +69,7 @@ public class NodeListConverterTest extends BaseSpringTest
|
||||
taskComponent = registry.getTaskComponent("jbpm");
|
||||
|
||||
// deploy latest review and approve process definition
|
||||
ClassPathResource processDef = new ClassPathResource("org/alfresco/repo/workflow/jbpm/review_and_approve_processdefinition.xml");
|
||||
ClassPathResource processDef = new ClassPathResource("alfresco/workflow/review_processdefinition.xml");
|
||||
WorkflowDeployment deployment = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML);
|
||||
testWorkflowDef = deployment.definition;
|
||||
assertNotNull(testWorkflowDef);
|
||||
|
@@ -69,7 +69,7 @@ public class ReviewAndApproveTest extends BaseSpringTest
|
||||
taskComponent = registry.getTaskComponent("jbpm");
|
||||
|
||||
// deploy latest review and approve process definition
|
||||
ClassPathResource processDef = new ClassPathResource("org/alfresco/repo/workflow/jbpm/review_and_approve_processdefinition.xml");
|
||||
ClassPathResource processDef = new ClassPathResource("alfresco/workflow/review_processdefinition.xml");
|
||||
WorkflowDeployment deployment = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML);
|
||||
testWorkflowDef = deployment.definition;
|
||||
assertNotNull(testWorkflowDef);
|
||||
@@ -97,9 +97,9 @@ public class ReviewAndApproveTest extends BaseSpringTest
|
||||
Map<QName, Serializable> params = new HashMap<QName, Serializable>();
|
||||
params.put(WorkflowModel.ASSOC_PACKAGE, testNodeRef);
|
||||
Date reviewDueDate = new Date();
|
||||
params.put(QName.createQName("http://www.alfresco.org/model/workflow/1.0", "reviewDueDate"), reviewDueDate);
|
||||
params.put(WorkflowModel.PROP_WORKFLOW_DUE_DATE, reviewDueDate);
|
||||
NodeRef reviewer = personService.getPerson("admin");
|
||||
params.put(QName.createQName("http://www.alfresco.org/model/workflow/1.0", "reviewer"), reviewer);
|
||||
params.put(WorkflowModel.ASSOC_ASSIGNEE, reviewer);
|
||||
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, params);
|
||||
assertNotNull(path);
|
||||
@@ -134,9 +134,9 @@ public class ReviewAndApproveTest extends BaseSpringTest
|
||||
params.put(WorkflowModel.ASSOC_PACKAGE, testNodeRef);
|
||||
params.put(WorkflowModel.PROP_COMPLETED_ITEMS, (Serializable)nodeRefs);
|
||||
Date reviewDueDate = new Date();
|
||||
params.put(QName.createQName("http://www.alfresco.org/model/workflow/1.0", "reviewDueDate"), reviewDueDate);
|
||||
params.put(WorkflowModel.PROP_WORKFLOW_DUE_DATE, reviewDueDate);
|
||||
NodeRef reviewer = personService.getPerson("admin");
|
||||
params.put(QName.createQName("http://www.alfresco.org/model/workflow/1.0", "reviewer"), reviewer);
|
||||
params.put(WorkflowModel.ASSOC_ASSIGNEE, reviewer);
|
||||
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, params);
|
||||
assertNotNull(path);
|
||||
|
@@ -1,70 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<process-definition xmlns="urn:jbpm.org:jpdl-3.1" name="wf:adhoc">
|
||||
|
||||
<swimlane name="initiator"/>
|
||||
|
||||
<start-state name="start">
|
||||
<task name="wf:submitAdhocTask" swimlane="initiator">
|
||||
<controller>
|
||||
<variable name="assignee" access="write" mapped-name="wf:assignee"/>
|
||||
<variable name="adhocduedate" access="write" mapped-name="wf:adhocDueDate"/>
|
||||
<variable name="adhocpriority" access="write" mapped-name="wf:adhocPriority"/>
|
||||
<variable name="adhocdescription" access="write" mapped-name="wf:adhocDescription"/>
|
||||
<variable name="notify" access="write" mapped-name="wf:notifyMe"/>
|
||||
<variable name="workflowpackage" access="write" mapped-name="bpm:package"/>
|
||||
<variable name="workflowcontext" access="write" mapped-name="bpm:context"/>
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="" to="adhoc"/>
|
||||
</start-state>
|
||||
|
||||
<swimlane name="assignee">
|
||||
<assignment actor-id="#{assignee.properties['cm:userName']}"/>
|
||||
</swimlane>
|
||||
|
||||
<task-node name="adhoc">
|
||||
<event type="task-create">
|
||||
<script>
|
||||
taskInstance.dueDate = adhocduedate;
|
||||
taskInstance.priority = adhocpriority;
|
||||
</script>
|
||||
</event>
|
||||
<task name="wf:adhocTask" swimlane="assignee">
|
||||
<controller>
|
||||
<variable name="adhocdescription" access="read" mapped-name="wf:adhocDescription"/>
|
||||
<variable name="workflowpackage" access="read" mapped-name="bpm:package"/>
|
||||
<variable name="workflowcontext" access="read" mapped-name="bpm:context"/>
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="" to="completed">
|
||||
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
|
||||
<script>
|
||||
if (notify)
|
||||
{
|
||||
var mail = actions.create("mail");
|
||||
mail.parameters.to = initiator.properties["cm:email"];
|
||||
mail.parameters.subject = "Adhoc Task " + adhocdescription;
|
||||
mail.parameters.from = assignee.properties["cm:email"];
|
||||
mail.parameters.text = "It's done";
|
||||
mail.execute(workflowpackage);
|
||||
}
|
||||
</script>
|
||||
</action>
|
||||
</transition>
|
||||
</task-node>
|
||||
|
||||
<task-node name="completed">
|
||||
<task name="wf:completedAdhocTask" swimlane="initiator">
|
||||
<controller>
|
||||
<variable name="adhocdescription" access="read" mapped-name="wf:adhocDescription"/>
|
||||
<variable name="workflowpackage" access="read" mapped-name="bpm:package"/>
|
||||
<variable name="workflowcontext" access="read" mapped-name="bpm:context"/>
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="" to="end"/>
|
||||
</task-node>
|
||||
|
||||
<end-state name="end"/>
|
||||
|
||||
</process-definition>
|
@@ -1,63 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<process-definition xmlns="urn:jbpm.org:jpdl-3.1" name="wf:review">
|
||||
|
||||
<swimlane name="initiator"/>
|
||||
|
||||
<start-state name="start">
|
||||
<task name="wf:submitReviewTask" swimlane="initiator">
|
||||
<controller>
|
||||
<variable name="reviewer" access="write" mapped-name="wf:reviewer"/>
|
||||
<variable name="reviewduedate" access="write" mapped-name="wf:reviewDueDate"/>
|
||||
<variable name="reviewpriority" access="write" mapped-name="wf:reviewPriority"/>
|
||||
<variable name="package" access="write" mapped-name="bpm:package"/>
|
||||
<variable name="context" access="write" mapped-name="bpm:context"/>
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="" to="review"/>
|
||||
</start-state>
|
||||
|
||||
<swimlane name="reviewer">
|
||||
<assignment actor-id="#{reviewer.properties['cm:userName']}"/>
|
||||
</swimlane>
|
||||
|
||||
<task-node name="review">
|
||||
<task name="wf:reviewTask" swimlane="reviewer">
|
||||
<event type="task-create">
|
||||
<script>
|
||||
taskInstance.dueDate = reviewduedate;
|
||||
taskInstance.priority = reviewpriority;
|
||||
</script>
|
||||
</event>
|
||||
<controller>
|
||||
<variable name="package" access="read,required" mapped-name="bpm:package"/>
|
||||
<variable name="context" access="read,required" mapped-name="bpm:context"/>
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="reject" to="rejected"/>
|
||||
<transition name="approve" to="approved"/>
|
||||
</task-node>
|
||||
|
||||
<task-node name="rejected">
|
||||
<task name="wf:rejectedTask" swimlane="initiator">
|
||||
<controller>
|
||||
<variable name="package" access="read,required" mapped-name="bpm:package"/>
|
||||
<variable name="context" access="read,required" mapped-name="bpm:context"/>
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="" to="end"/>
|
||||
</task-node>
|
||||
|
||||
<task-node name="approved">
|
||||
<task name="wf:approvedTask" swimlane="initiator">
|
||||
<controller>
|
||||
<variable name="package" access="read,required" mapped-name="bpm:package"/>
|
||||
<variable name="context" access="read,required" mapped-name="bpm:context"/>
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="" to="end"/>
|
||||
</task-node>
|
||||
|
||||
<end-state name="end"/>
|
||||
|
||||
</process-definition>
|
@@ -1,57 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<process-definition xmlns="urn:jbpm.org:jpdl-3.1" name="test_script">
|
||||
<swimlane name="initiator"></swimlane>
|
||||
<swimlane name="initiator"></swimlane>
|
||||
|
||||
<start-state name="start">
|
||||
<task name="submit" swimlane="initiator">
|
||||
<event type="task-assign">
|
||||
<start-state name="start">
|
||||
<task name="submit" swimlane="initiator">
|
||||
<event type="task-assign">
|
||||
<script>
|
||||
System.out.println("taskInstance.create: " + taskInstance.create);
|
||||
System.out.println("taskInstance.description: " + taskInstance.description);
|
||||
</script>
|
||||
</event>
|
||||
<controller>
|
||||
<variable name="testNode" access="write,required" />
|
||||
<variable name="bpm_workflowDescription" access="write" />
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="" to="doit" />
|
||||
</start-state>
|
||||
|
||||
<node name="doit">
|
||||
<event type="node-enter">
|
||||
<script>
|
||||
System.out.println("taskInstance.create: " + taskInstance.create);
|
||||
<expression>
|
||||
System.out.println("testNode.created: " + testNode.properties{"cm:created"});
|
||||
System.out.println("test node " + testNode.name + " contains " + testNode.children.length + " children");
|
||||
</expression>
|
||||
<variable name="testNode" access="read" />
|
||||
</script>
|
||||
</event>
|
||||
<controller>
|
||||
<variable name="testNode" access="write,required" />
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="" to="doit"/>
|
||||
</start-state>
|
||||
|
||||
<node name="doit">
|
||||
<event type="node-enter">
|
||||
<script>
|
||||
<expression>
|
||||
System.out.println("testNode.created: " + testNode.properties{"cm:created"});
|
||||
System.out.println("test node " + testNode.name + " contains " + testNode.children.length + " children");
|
||||
</expression>
|
||||
<variable name="testNode" access="read"/>
|
||||
</script>
|
||||
</event>
|
||||
<event type="node-enter">
|
||||
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
|
||||
<script>
|
||||
<!-- following line fails as it attempts to convert properties of children to javascript objects -->
|
||||
<!-- except the beanshell line above has already pre-created the children without the javascript scope -->
|
||||
<!-- object -->
|
||||
<!-- var result = "testNode.created: " + testNode.properties["cm:created"] + ", testNode.children.length: " + testNode.children[0].properties["cm:name"]; -->
|
||||
<expression>
|
||||
var result = "testNode.created: " + testNode.properties["cm:created"] + ", testNode.children.length: " + testNode.children.length;
|
||||
result;
|
||||
</expression>
|
||||
<variable name="testNode" access="read"/>
|
||||
<variable name="alfrescoScriptResult" access="write"/>
|
||||
</script>
|
||||
</action>
|
||||
</event>
|
||||
<transition name="" to="end"/>
|
||||
</node>
|
||||
|
||||
<end-state name="end">
|
||||
<event type="node-enter">
|
||||
<script>
|
||||
System.out.println("javascript: " + alfrescoScriptResult);
|
||||
</script>
|
||||
</event>
|
||||
</end-state>
|
||||
|
||||
</event>
|
||||
<event type="node-enter">
|
||||
<action
|
||||
class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
|
||||
<script>
|
||||
<!-- following line fails as it attempts to convert properties of children to javascript objects -->
|
||||
<!-- except the beanshell line above has already pre-created the children without the javascript scope -->
|
||||
<!-- object -->
|
||||
<!-- var result = "testNode.created: " + testNode.properties["cm:created"] + ", testNode.children.length: " + testNode.children[0].properties["cm:name"]; -->
|
||||
<expression>
|
||||
var result = "testNode.created: " + theTestNode.properties["cm:created"] + ", theTestNode.children.length: " + theTestNode.children.length;
|
||||
if (logger.isLoggingEnabled())
|
||||
{
|
||||
logger.log(result);
|
||||
}
|
||||
result;
|
||||
</expression>
|
||||
<variable name="testNode" access="read" mapped-name="theTestNode" />
|
||||
<variable name="alfrescoScriptResult" access="write" />
|
||||
</script>
|
||||
</action>
|
||||
</event>
|
||||
<transition name="" to="end" />
|
||||
</node>
|
||||
|
||||
<end-state name="end">
|
||||
<event type="node-enter">
|
||||
<script>
|
||||
System.out.println("javascript: " + alfrescoScriptResult);
|
||||
System.out.println("bpm_workflowDescription: " + bpm_description);
|
||||
</script>
|
||||
</event>
|
||||
</end-state>
|
||||
|
||||
</process-definition>
|
||||
|
Reference in New Issue
Block a user