mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Big honkin' merge from head. Sheesh!
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3617 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
96
source/java/org/alfresco/repo/workflow/BPMEngine.java
Normal file
96
source/java/org/alfresco/repo/workflow/BPMEngine.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
|
||||
/**
|
||||
* Base functionality for a plug-in BPM Engine
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class BPMEngine implements InitializingBean
|
||||
{
|
||||
private BPMEngineRegistry registry;
|
||||
private String engineId;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the BPM Engine Registry
|
||||
*
|
||||
* @param registry the registry
|
||||
*/
|
||||
public void setBPMEngineRegistry(BPMEngineRegistry registry)
|
||||
{
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the BPM Engine Id
|
||||
*
|
||||
* @param engineId the id
|
||||
*/
|
||||
public void setEngineId(String engineId)
|
||||
{
|
||||
this.engineId = engineId;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
if (engineId == null || engineId.length() == 0)
|
||||
{
|
||||
throw new WorkflowException("Engine Id not specified");
|
||||
}
|
||||
|
||||
if (this instanceof WorkflowComponent)
|
||||
{
|
||||
registry.registerWorkflowComponent(engineId, (WorkflowComponent)this);
|
||||
}
|
||||
if (this instanceof TaskComponent)
|
||||
{
|
||||
registry.registerTaskComponent(engineId, (TaskComponent)this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a global Id for use outside of the engine
|
||||
*
|
||||
* @param localId the local engine id
|
||||
* @return the global id
|
||||
*/
|
||||
protected String createGlobalId(String localId)
|
||||
{
|
||||
return BPMEngineRegistry.createGlobalId(engineId, localId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a local Id from a global Id
|
||||
*
|
||||
* @param globalId the global id
|
||||
* @return the local id
|
||||
*/
|
||||
protected String createLocalId(String globalId)
|
||||
{
|
||||
return BPMEngineRegistry.getLocalId(globalId);
|
||||
}
|
||||
}
|
193
source/java/org/alfresco/repo/workflow/BPMEngineRegistry.java
Normal file
193
source/java/org/alfresco/repo/workflow/BPMEngineRegistry.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
|
||||
/**
|
||||
* BPM Engine Registry
|
||||
*
|
||||
* Responsible for managing the list of registered BPM Engines for the
|
||||
* following components:
|
||||
*
|
||||
* - Workflow Component
|
||||
* - Task Component
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class BPMEngineRegistry
|
||||
{
|
||||
/** ID seperator used in global Ids */
|
||||
private static final String ID_SEPERATOR = "$";
|
||||
private static final String ID_SEPERATOR_REGEX = "\\$";
|
||||
|
||||
/** Logging support */
|
||||
private static Log logger = LogFactory.getLog("org.alfresco.repo.workflow");
|
||||
|
||||
private Map<String, WorkflowComponent> workflowComponents;
|
||||
private Map<String, TaskComponent> taskComponents;
|
||||
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*/
|
||||
public BPMEngineRegistry()
|
||||
{
|
||||
workflowComponents = new HashMap<String, WorkflowComponent>();
|
||||
taskComponents = new HashMap<String, TaskComponent>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a BPM Engine Workflow Component
|
||||
*
|
||||
* @param engineId engine id
|
||||
* @param engine implementing engine
|
||||
*/
|
||||
public void registerWorkflowComponent(String engineId, WorkflowComponent engine)
|
||||
{
|
||||
if (workflowComponents.containsKey(engineId))
|
||||
{
|
||||
throw new WorkflowException("Workflow Component already registered for engine id '" + engineId + "'");
|
||||
}
|
||||
workflowComponents.put(engineId, engine);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("Registered Workflow Component '" + engineId + "' (" + engine.getClass() + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all registered Workflow Components
|
||||
*
|
||||
* @return array of engine ids
|
||||
*/
|
||||
public String[] getWorkflowComponents()
|
||||
{
|
||||
return workflowComponents.keySet().toArray(new String[workflowComponents.keySet().size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific BPM Engine Workflow Component
|
||||
*
|
||||
* @param engineId engine id
|
||||
* @return the Workflow Component
|
||||
*/
|
||||
public WorkflowComponent getWorkflowComponent(String engineId)
|
||||
{
|
||||
return workflowComponents.get(engineId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a BPM Engine Task Component
|
||||
*
|
||||
* @param engineId engine id
|
||||
* @param engine implementing engine
|
||||
*/
|
||||
public void registerTaskComponent(String engineId, TaskComponent engine)
|
||||
{
|
||||
if (taskComponents.containsKey(engineId))
|
||||
{
|
||||
throw new WorkflowException("Task Component already registered for engine id '" + engineId + "'");
|
||||
}
|
||||
taskComponents.put(engineId, engine);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("Registered Task Component '" + engineId + "' (" + engine.getClass() + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all registered Task Components
|
||||
*
|
||||
* @return array of engine ids
|
||||
*/
|
||||
public String[] getTaskComponents()
|
||||
{
|
||||
return taskComponents.keySet().toArray(new String[taskComponents.keySet().size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific BPM Engine Task Component
|
||||
*
|
||||
* @param engineId engine id
|
||||
* @return the Workflow Component
|
||||
*/
|
||||
public TaskComponent getTaskComponent(String engineId)
|
||||
{
|
||||
return taskComponents.get(engineId);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// BPM Engine Id support
|
||||
//
|
||||
|
||||
/**
|
||||
* Construct a global Id
|
||||
*
|
||||
* @param engineId engine id
|
||||
* @param localId engine local id
|
||||
* @return the global id
|
||||
*/
|
||||
public static String createGlobalId(String engineId, String localId)
|
||||
{
|
||||
return engineId + ID_SEPERATOR + localId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Break apart a global id into its engine and local ids
|
||||
*
|
||||
* @param globalId the global id
|
||||
* @return array containing engine id and global id in that order
|
||||
*/
|
||||
public static String[] getGlobalIdParts(String globalId)
|
||||
{
|
||||
String[] parts = globalId.split(ID_SEPERATOR_REGEX);
|
||||
if (parts.length != 2)
|
||||
{
|
||||
throw new WorkflowException("Invalid Global Id '" + globalId + "'");
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the engine id from a global id
|
||||
*
|
||||
* @param globalId the global id
|
||||
* @return the engine id
|
||||
*/
|
||||
public static String getEngineId(String globalId)
|
||||
{
|
||||
return getGlobalIdParts(globalId)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local id from a global id
|
||||
*
|
||||
* @param globalId the global id
|
||||
* @return the local id
|
||||
*/
|
||||
public static String getLocalId(String globalId)
|
||||
{
|
||||
return getGlobalIdParts(globalId)[1];
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
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.WorkflowService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Simple workflow action executor
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class StartWorkflowActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
public static final String NAME = "start-workflow";
|
||||
|
||||
public static final String PARAM_WORKFLOW_NAME = "workflowName";
|
||||
|
||||
// action dependencies
|
||||
private NamespaceService namespaceService;
|
||||
private WorkflowService workflowService;
|
||||
private NodeService nodeService;
|
||||
|
||||
|
||||
/**
|
||||
* @param namespaceService
|
||||
*/
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param workflowService
|
||||
*/
|
||||
public void setWorkflowService(WorkflowService workflowService)
|
||||
{
|
||||
this.workflowService = workflowService;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.action.ParameterizedItemAbstractBase#getAdhocPropertiesAllowed()
|
||||
*/
|
||||
@Override
|
||||
protected boolean getAdhocPropertiesAllowed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List)
|
||||
*/
|
||||
@Override
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@Override
|
||||
protected void executeImpl(Action ruleAction, NodeRef actionedUponNodeRef)
|
||||
{
|
||||
// retrieve workflow definition
|
||||
String workflowName = (String)ruleAction.getParameterValue(PARAM_WORKFLOW_NAME);
|
||||
WorkflowDefinition def = workflowService.getDefinitionByName(workflowName);
|
||||
|
||||
// create workflow package to contain actioned upon node
|
||||
NodeRef workflowPackage = (NodeRef)ruleAction.getParameterValue(WorkflowModel.ASSOC_PACKAGE.toPrefixString(namespaceService));
|
||||
workflowPackage = workflowService.createPackage(workflowPackage);
|
||||
ChildAssociationRef childAssoc = nodeService.getPrimaryParent(actionedUponNodeRef);
|
||||
nodeService.addChild(workflowPackage, actionedUponNodeRef, ContentModel.ASSOC_CONTAINS, childAssoc.getQName());
|
||||
|
||||
// build map of workflow start task parameters
|
||||
Map<String, Serializable> paramValues = ruleAction.getParameterValues();
|
||||
Map<QName, Serializable> workflowParameters = new HashMap<QName, Serializable>();
|
||||
workflowParameters.put(WorkflowModel.ASSOC_PACKAGE, workflowPackage);
|
||||
for (Map.Entry<String, Serializable> entry : paramValues.entrySet())
|
||||
{
|
||||
if (!entry.getKey().equals(PARAM_WORKFLOW_NAME))
|
||||
{
|
||||
QName qname = QName.createQName(entry.getKey(), namespaceService);
|
||||
Serializable value = entry.getValue();
|
||||
workflowParameters.put(qname, value);
|
||||
}
|
||||
}
|
||||
|
||||
// start the workflow
|
||||
workflowService.startWorkflow(def.id, workflowParameters);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ActionImpl;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
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.security.PersonService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.alfresco.util.GUID;
|
||||
|
||||
/**
|
||||
* Add features action execution test
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class StartWorkflowActionExecuterTest extends BaseSpringTest
|
||||
{
|
||||
private NodeService nodeService;
|
||||
private NamespaceService namespaceService;
|
||||
private PersonService personService;
|
||||
private NodeRef rootNodeRef;
|
||||
private NodeRef nodeRef;
|
||||
private StartWorkflowActionExecuter executer;
|
||||
|
||||
|
||||
/**
|
||||
* Called at the begining of all tests
|
||||
*/
|
||||
@Override
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
this.nodeService = (NodeService)this.applicationContext.getBean("nodeService");
|
||||
this.namespaceService = (NamespaceService)this.applicationContext.getBean("namespaceService");
|
||||
this.personService = (PersonService)this.applicationContext.getBean("personService");
|
||||
|
||||
AuthenticationComponent authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent");
|
||||
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
|
||||
|
||||
// Create the store and get the root node
|
||||
rootNodeRef = nodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "spacesStore"));
|
||||
this.nodeRef = this.nodeService.createNode(
|
||||
this.rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{test}testnode"),
|
||||
ContentModel.TYPE_CONTENT).getChildRef();
|
||||
|
||||
// Get the executer instance
|
||||
this.executer = (StartWorkflowActionExecuter)this.applicationContext.getBean(StartWorkflowActionExecuter.NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execution
|
||||
*/
|
||||
public void testExecution()
|
||||
{
|
||||
// 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());
|
||||
NodeRef reviewer = personService.getPerson("admin");
|
||||
action.setParameterValue(WorkflowModel.ASSOC_REVIEWER.toPrefixString(namespaceService), reviewer);
|
||||
executer.execute(action, this.nodeRef);
|
||||
}
|
||||
}
|
102
source/java/org/alfresco/repo/workflow/TaskComponent.java
Normal file
102
source/java/org/alfresco/repo/workflow/TaskComponent.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
|
||||
/**
|
||||
* SPI to be implemented by a BPM Engine that provides Task management.
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public interface TaskComponent
|
||||
{
|
||||
|
||||
/**
|
||||
* Gets a Task by unique Id
|
||||
*
|
||||
* @param taskId the task id
|
||||
* @return the task
|
||||
*/
|
||||
public WorkflowTask getTaskById(String taskId);
|
||||
|
||||
/**
|
||||
* Gets all tasks assigned to the specified authority
|
||||
*
|
||||
* @param authority the authority
|
||||
* @param state filter by specified workflow task state
|
||||
* @return the list of assigned tasks
|
||||
*/
|
||||
public List<WorkflowTask> getAssignedTasks(String authority, WorkflowTaskState state);
|
||||
|
||||
/**
|
||||
* Gets the pooled tasks available to the specified authority
|
||||
*
|
||||
* @param authority the authority
|
||||
* @return the list of pooled tasks
|
||||
*/
|
||||
public List<WorkflowTask> getPooledTasks(List<String> authorities);
|
||||
|
||||
/**
|
||||
* Update the Properties and Associations of a Task
|
||||
*
|
||||
* @param taskId the task id to update
|
||||
* @param properties the map of properties to set on the task (or null, if none to set)
|
||||
* @param add the map of items to associate with the task (or null, if none to add)
|
||||
* @param remove the map of items to dis-associate with the task (or null, if none to remove)
|
||||
* @return the update task
|
||||
*/
|
||||
public WorkflowTask updateTask(String taskId, Map<QName, Serializable> properties, Map<QName, List<NodeRef>> add, Map<QName, List<NodeRef>> remove);
|
||||
|
||||
/**
|
||||
* Start the specified Task
|
||||
*
|
||||
* Note: this is an optional task operation. It may be used to track
|
||||
* when work started on a task as well as resume a suspended task.
|
||||
*
|
||||
* @param taskId the task to start
|
||||
* @return the updated task
|
||||
*/
|
||||
public WorkflowTask startTask(String taskId);
|
||||
|
||||
/**
|
||||
* Suspend the specified Task
|
||||
*
|
||||
* @param taskId
|
||||
* @return the update task
|
||||
*/
|
||||
public WorkflowTask suspendTask(String taskId);
|
||||
|
||||
/**
|
||||
* End the Task (i.e. complete the task)
|
||||
*
|
||||
* @param taskId the task id to end
|
||||
* @param transition the task transition to take on completion (or null, for the default transition)
|
||||
* @return the updated task
|
||||
*/
|
||||
public WorkflowTask endTask(String taskId, String transitionId);
|
||||
|
||||
}
|
||||
|
156
source/java/org/alfresco/repo/workflow/WorkflowComponent.java
Normal file
156
source/java/org/alfresco/repo/workflow/WorkflowComponent.java
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDeployment;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowInstance;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowPath;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
|
||||
/**
|
||||
* SPI to be implemented by a BPM Engine that provides Workflow instance management.
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public interface WorkflowComponent
|
||||
{
|
||||
|
||||
//
|
||||
// Workflow Definition Support
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* Deploy a Workflow Definition
|
||||
*
|
||||
* @param workflowDefinition the content object containing the definition
|
||||
* @param mimetype (optional) the mime type of the workflow definition
|
||||
* @return workflow deployment descriptor
|
||||
*/
|
||||
public WorkflowDeployment deployDefinition(InputStream workflowDefinition, String mimetype);
|
||||
|
||||
/**
|
||||
* Is the specified Workflow Definition already deployed?
|
||||
*
|
||||
* Note: the notion of "already deployed" may differ between bpm engines. For example,
|
||||
* different versions of the same process may be considered equal.
|
||||
*
|
||||
* @param workflowDefinition the definition to check
|
||||
* @param mimetype the mimetype of the definition
|
||||
* @return true => already deployed
|
||||
*/
|
||||
public boolean isDefinitionDeployed(InputStream workflowDefinition, String mimetype);
|
||||
|
||||
/**
|
||||
* Undeploy an exisiting Workflow Definition
|
||||
*
|
||||
* TODO: Determine behaviour when "in-flight" workflow instances exist
|
||||
*
|
||||
* @param workflowDefinitionId the id of the definition to undeploy
|
||||
*/
|
||||
public void undeployDefinition(String workflowDefinitionId);
|
||||
|
||||
/**
|
||||
* Gets all deployed Workflow Definitions
|
||||
*
|
||||
* @return the deployed workflow definitions
|
||||
*/
|
||||
public List<WorkflowDefinition> getDefinitions();
|
||||
|
||||
/**
|
||||
* Gets a Workflow Definition by unique Id
|
||||
*
|
||||
* @param workflowDefinitionId the workflow definition id
|
||||
* @return the deployed workflow definition
|
||||
*/
|
||||
public WorkflowDefinition getDefinitionById(String workflowDefinitionId);
|
||||
|
||||
/**
|
||||
* Gets a Workflow Definition by unique name
|
||||
*
|
||||
* @param workflowName workflow name e.g. jbpm://review
|
||||
* @return the deployed workflow definition
|
||||
*/
|
||||
public WorkflowDefinition getDefinitionByName(String workflowName);
|
||||
|
||||
|
||||
//
|
||||
// Workflow Instance Support
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* Start a Workflow Instance
|
||||
*
|
||||
* @param workflowDefinitionId the workflow definition id
|
||||
* @param parameters the initial set of parameters used to populate the "Start Task" properties
|
||||
* @return the initial workflow path
|
||||
*/
|
||||
public WorkflowPath startWorkflow(String workflowDefinitionId, Map<QName, Serializable> parameters);
|
||||
|
||||
/**
|
||||
* Gets all "in-flight" workflow instances of the specified Workflow Definition
|
||||
*
|
||||
* @param workflowDefinitionId the workflow definition id
|
||||
* @return the list of "in-fligth" workflow instances
|
||||
*/
|
||||
public List<WorkflowInstance> getActiveWorkflows(String workflowDefinitionId);
|
||||
|
||||
/**
|
||||
* Gets all Paths for the specified Workflow instance
|
||||
*
|
||||
* @param workflowId workflow instance id
|
||||
* @return the list of workflow paths
|
||||
*/
|
||||
public List<WorkflowPath> getWorkflowPaths(String workflowId);
|
||||
|
||||
/**
|
||||
* Cancel an "in-fligth" Workflow instance
|
||||
*
|
||||
* @param workflowId the workflow instance to cancel
|
||||
* @return an updated representation of the workflow instance
|
||||
*/
|
||||
public WorkflowInstance cancelWorkflow(String workflowId);
|
||||
|
||||
/**
|
||||
* Signal the transition from one Workflow Node to another within an "in-flight"
|
||||
* process.
|
||||
*
|
||||
* @param pathId the workflow path to signal on
|
||||
* @param transition the transition to follow (or null, for the default transition)
|
||||
* @return the updated workflow path
|
||||
*/
|
||||
public WorkflowPath signal(String pathId, String transitionId);
|
||||
|
||||
/**
|
||||
* Gets all Tasks associated with the specified path
|
||||
*
|
||||
* @param pathId the path id
|
||||
* @return the list of associated tasks
|
||||
*/
|
||||
public List<WorkflowTask> getTasksForWorkflowPath(String pathId);
|
||||
|
||||
}
|
||||
|
191
source/java/org/alfresco/repo/workflow/WorkflowDeployer.java
Normal file
191
source/java/org/alfresco/repo/workflow/WorkflowDeployer.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.service.cmr.view.ImporterException;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDeployment;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
|
||||
/**
|
||||
* Alfresco bootstrap Process deployment.
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class WorkflowDeployer implements ApplicationListener
|
||||
{
|
||||
// Logging support
|
||||
private static Log logger = LogFactory.getLog("org.alfresco.repo.workflow");
|
||||
|
||||
// Workflow Definition Properties (used in setWorkflowDefinitions)
|
||||
public static final String ENGINE_ID = "engineId";
|
||||
public static final String LOCATION = "location";
|
||||
public static final String MIMETYPE = "mimetype";
|
||||
public static final String REDEPLOY = "redeploy";
|
||||
|
||||
// Dependencies
|
||||
private TransactionService transactionService;
|
||||
private WorkflowService workflowService;
|
||||
private AuthenticationComponent authenticationComponent;
|
||||
private List<Properties> workflowDefinitions;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the Transaction Service
|
||||
*
|
||||
* @param userTransaction the transaction service
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the namespace service
|
||||
*
|
||||
* @param namespaceService the namespace service
|
||||
*/
|
||||
public void setWorkflowService(WorkflowService workflowService)
|
||||
{
|
||||
this.workflowService = workflowService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the authentication component
|
||||
*
|
||||
* @param authenticationComponent
|
||||
*/
|
||||
public void setAuthenticationComponent(AuthenticationComponent authenticationComponent)
|
||||
{
|
||||
this.authenticationComponent = authenticationComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Workflow Definitions
|
||||
*
|
||||
* @param workflowDefinitions
|
||||
*/
|
||||
public void setWorkflowDefinitions(List<Properties> workflowDefinitions)
|
||||
{
|
||||
this.workflowDefinitions = workflowDefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy the Workflow Definitions
|
||||
*/
|
||||
public void deploy()
|
||||
{
|
||||
if (transactionService == null)
|
||||
{
|
||||
throw new ImporterException("Transaction Service must be provided");
|
||||
}
|
||||
if (authenticationComponent == null)
|
||||
{
|
||||
throw new ImporterException("Authentication Component must be provided");
|
||||
}
|
||||
if (workflowService == null)
|
||||
{
|
||||
throw new ImporterException("Workflow Service must be provided");
|
||||
}
|
||||
|
||||
UserTransaction userTransaction = transactionService.getUserTransaction();
|
||||
authenticationComponent.setSystemUserAsCurrentUser();
|
||||
|
||||
try
|
||||
{
|
||||
userTransaction.begin();
|
||||
|
||||
// bootstrap the workflow definitions
|
||||
if (workflowDefinitions != null)
|
||||
{
|
||||
for (Properties workflowDefinition : workflowDefinitions)
|
||||
{
|
||||
// retrieve workflow specification
|
||||
String engineId = workflowDefinition.getProperty(ENGINE_ID);
|
||||
if (engineId == null || engineId.length() == 0)
|
||||
{
|
||||
throw new WorkflowException("Workflow Engine Id must be provided");
|
||||
}
|
||||
String location = workflowDefinition.getProperty(LOCATION);
|
||||
if (location == null || location.length() == 0)
|
||||
{
|
||||
throw new WorkflowException("Workflow definition location must be provided");
|
||||
}
|
||||
Boolean redeploy = Boolean.valueOf(workflowDefinition.getProperty(REDEPLOY));
|
||||
String mimetype = workflowDefinition.getProperty(MIMETYPE);
|
||||
|
||||
// retrieve input stream on workflow definition
|
||||
ClassPathResource workflowResource = new ClassPathResource(location);
|
||||
|
||||
// deploy workflow definition
|
||||
if (!redeploy && workflowService.isDefinitionDeployed(engineId, workflowResource.getInputStream(), mimetype))
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Workflow deployer: Definition '" + location + "' already deployed");
|
||||
}
|
||||
else
|
||||
{
|
||||
WorkflowDeployment deployment = workflowService.deployDefinition(engineId, workflowResource.getInputStream(), mimetype);
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("Workflow deployer: Deployed process definition '" + deployment.definition.title + "' (version " + deployment.definition.version + ") from '" + location + "' with " + deployment.problems.length + " problems");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
userTransaction.commit();
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
// rollback the transaction
|
||||
try { if (userTransaction != null) {userTransaction.rollback();} } catch (Exception ex) {}
|
||||
try {authenticationComponent.clearCurrentSecurityContext(); } catch (Exception ex) {}
|
||||
throw new AlfrescoRuntimeException("Workflow deployment failed", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
authenticationComponent.clearCurrentSecurityContext();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
*/
|
||||
public void onApplicationEvent(ApplicationEvent event)
|
||||
{
|
||||
if (event instanceof ContextRefreshedEvent)
|
||||
{
|
||||
deploy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
70
source/java/org/alfresco/repo/workflow/WorkflowModel.java
Normal file
70
source/java/org/alfresco/repo/workflow/WorkflowModel.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
|
||||
/**
|
||||
* Workflow Model Constants
|
||||
*/
|
||||
public interface WorkflowModel
|
||||
{
|
||||
|
||||
//
|
||||
// Base Business Process Management Definitions
|
||||
//
|
||||
|
||||
// task constants
|
||||
static final QName TYPE_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "task");
|
||||
static final QName PROP_TASK_ID = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "taskId");
|
||||
static final QName PROP_START_DATE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "startDate");
|
||||
static final QName PROP_DUE_DATE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "dueDate");
|
||||
static final QName PROP_COMPLETION_DATE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "completionDate");
|
||||
static final QName PROP_PRIORITY = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "priority");
|
||||
static final QName PROP_STATUS = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "status");
|
||||
static final QName PROP_PERCENT_COMPLETE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "percentComplete");
|
||||
static final QName PROP_COMPLETED_ITEMS = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "completedItems");
|
||||
static final QName ASSOC_POOLED_ACTORS = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "pooledActors");
|
||||
|
||||
// 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_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 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");
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
|
||||
/**
|
||||
* Contract for managing Workflow Packages. A package is a container
|
||||
* of Content that's routed through a Workflow.
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public interface WorkflowPackageComponent
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a Workflow Package (a container of content to route through the Workflow).
|
||||
*
|
||||
* If an existing container is supplied, it's supplemented with the workflow package aspect.
|
||||
*
|
||||
* @param container (optional) a pre-created container (e.g. folder, versioned folder or layered folder)
|
||||
* @return the workflow package
|
||||
*/
|
||||
public NodeRef createPackage(NodeRef container);
|
||||
|
||||
// TODO: Support for finding packages via meta-data of WorkflowPackage aspect
|
||||
|
||||
}
|
210
source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java
Normal file
210
source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.GUID;
|
||||
|
||||
|
||||
/**
|
||||
* Alfresco implementation of Workflow Package where the package is stored
|
||||
* within the Alfresco Repository.
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class WorkflowPackageImpl implements WorkflowPackageComponent
|
||||
{
|
||||
private final static String PACKAGE_FOLDER = "Workflow Packages";
|
||||
|
||||
// service dependencies
|
||||
private ImporterBootstrap bootstrap;
|
||||
private SearchService searchService;
|
||||
private NodeService nodeService;
|
||||
private NamespaceService namespaceService;
|
||||
private FileFolderService fileFolderService;
|
||||
private NodeRef systemWorkflowContainer = null;
|
||||
|
||||
|
||||
/**
|
||||
* @param bootstrap the importer bootstrap for the store to place workflow items into
|
||||
*/
|
||||
public void setImporterBootstrap(ImporterBootstrap bootstrap)
|
||||
{
|
||||
this.bootstrap = bootstrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileFolderService file folder service
|
||||
*/
|
||||
public void setFileFolderService(FileFolderService fileFolderService)
|
||||
{
|
||||
this.fileFolderService = fileFolderService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchService search service
|
||||
*/
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param namespaceService namespace service
|
||||
*/
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowPackageComponent#createPackage(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public NodeRef createPackage(NodeRef container)
|
||||
{
|
||||
// create a container, if one is not specified
|
||||
if (container == null)
|
||||
{
|
||||
// create simple folder in workflow system folder
|
||||
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();
|
||||
}
|
||||
|
||||
// attach workflow package
|
||||
if (nodeService.hasAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE))
|
||||
{
|
||||
throw new WorkflowException("Container '" + container + "' is already a workflow package.");
|
||||
}
|
||||
nodeService.addAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE, null);
|
||||
|
||||
// return container
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the system workflow container for storing workflow related items
|
||||
*
|
||||
* @return the system workflow container
|
||||
*/
|
||||
private NodeRef getSystemWorkflowContainer()
|
||||
{
|
||||
if (systemWorkflowContainer == null)
|
||||
{
|
||||
NodeRef systemContainer = findSystemContainer();
|
||||
systemWorkflowContainer = findSystemWorkflowContainer(systemContainer);
|
||||
if (systemWorkflowContainer == null)
|
||||
{
|
||||
throw new WorkflowException("Unable to find system workflow folder - does not exist.");
|
||||
}
|
||||
}
|
||||
return systemWorkflowContainer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the system workflow container
|
||||
*
|
||||
* @param systemContainer the system container
|
||||
* @return the system workflow container
|
||||
*/
|
||||
private NodeRef findSystemWorkflowContainer(NodeRef systemContainer)
|
||||
{
|
||||
String path = bootstrap.getConfiguration().getProperty("system.workflow_container.childname");
|
||||
if (path == null)
|
||||
{
|
||||
throw new WorkflowException("Unable to locate workflow system container - path not specified");
|
||||
}
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(systemContainer, path, null, namespaceService, false);
|
||||
if (nodeRefs != null && nodeRefs.size() > 0)
|
||||
{
|
||||
systemWorkflowContainer = nodeRefs.get(0);
|
||||
}
|
||||
return systemWorkflowContainer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the system container
|
||||
*
|
||||
* @return the system container
|
||||
*/
|
||||
private NodeRef findSystemContainer()
|
||||
{
|
||||
String path = bootstrap.getConfiguration().getProperty("system.system_container.childname");
|
||||
if (path == null)
|
||||
{
|
||||
throw new WorkflowException("Unable to locate system container - path not specified");
|
||||
}
|
||||
NodeRef root = nodeService.getRootNode(bootstrap.getStoreRef());
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(root, path, null, namespaceService, false);
|
||||
if (nodeRefs == null || nodeRefs.size() == 0)
|
||||
{
|
||||
throw new WorkflowException("Unable to locate system container - path not found");
|
||||
}
|
||||
return nodeRefs.get(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the System Workflow Container
|
||||
*
|
||||
* @return the system workflow container
|
||||
*/
|
||||
public NodeRef createSystemWorkflowContainer()
|
||||
{
|
||||
NodeRef systemContainer = findSystemContainer();
|
||||
NodeRef systemWorkflowContainer = findSystemWorkflowContainer(systemContainer);
|
||||
if (systemWorkflowContainer == null)
|
||||
{
|
||||
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);
|
||||
systemWorkflowContainer = childRef.getChildRef();
|
||||
}
|
||||
return systemWorkflowContainer;
|
||||
}
|
||||
|
||||
}
|
330
source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java
Normal file
330
source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDeployment;
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* Default Alfresco Workflow Service whose implementation is backed by registered
|
||||
* BPM Engine plug-in components.
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class WorkflowServiceImpl implements WorkflowService
|
||||
{
|
||||
// Logging support
|
||||
private static Log logger = LogFactory.getLog("org.alfresco.repo.workflow");
|
||||
|
||||
// Dependent services
|
||||
private BPMEngineRegistry registry;
|
||||
private WorkflowPackageComponent workflowPackageComponent;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the BPM Engine Registry
|
||||
*
|
||||
* @param registry bpm engine registry
|
||||
*/
|
||||
public void setBPMEngineRegistry(BPMEngineRegistry registry)
|
||||
{
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Workflow Package Component
|
||||
*
|
||||
* @param workflowPackage workflow package component
|
||||
*/
|
||||
public void setWorkflowPackageComponent(WorkflowPackageComponent workflowPackageComponent)
|
||||
{
|
||||
this.workflowPackageComponent = workflowPackageComponent;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#deployDefinition(java.lang.String, java.io.InputStream, java.lang.String)
|
||||
*/
|
||||
public WorkflowDeployment deployDefinition(String engineId, InputStream workflowDefinition, String mimetype)
|
||||
{
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
WorkflowDeployment deployment = component.deployDefinition(workflowDefinition, mimetype);
|
||||
|
||||
if (logger.isDebugEnabled() && deployment.problems.length > 0)
|
||||
{
|
||||
for (String problem : deployment.problems)
|
||||
{
|
||||
logger.debug("Workflow definition '" + deployment.definition.title + "' problem: " + problem);
|
||||
}
|
||||
}
|
||||
|
||||
return deployment;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#isDefinitionDeployed(java.lang.String, java.io.InputStream, java.lang.String)
|
||||
*/
|
||||
public boolean isDefinitionDeployed(String engineId, InputStream workflowDefinition, String mimetype)
|
||||
{
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
return component.isDefinitionDeployed(workflowDefinition, mimetype);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#deployDefinition(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public WorkflowDeployment deployDefinition(NodeRef definitionContent)
|
||||
{
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#undeployDefinition(java.lang.String)
|
||||
*/
|
||||
public void undeployDefinition(String workflowDefinitionId)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(workflowDefinitionId);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
component.undeployDefinition(workflowDefinitionId);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getDefinitions()
|
||||
*/
|
||||
public List<WorkflowDefinition> getDefinitions()
|
||||
{
|
||||
List<WorkflowDefinition> definitions = new ArrayList<WorkflowDefinition>(10);
|
||||
String[] ids = registry.getWorkflowComponents();
|
||||
for (String id: ids)
|
||||
{
|
||||
WorkflowComponent component = registry.getWorkflowComponent(id);
|
||||
definitions.addAll(component.getDefinitions());
|
||||
}
|
||||
return Collections.unmodifiableList(definitions);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getDefinitionById(java.lang.String)
|
||||
*/
|
||||
public WorkflowDefinition getDefinitionById(String workflowDefinitionId)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(workflowDefinitionId);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
return component.getDefinitionById(workflowDefinitionId);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getDefinitionByName(java.lang.String)
|
||||
*/
|
||||
public WorkflowDefinition getDefinitionByName(String workflowName)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(workflowName);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
return component.getDefinitionByName(workflowName);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#startWorkflow(java.lang.String, java.util.Map)
|
||||
*/
|
||||
public WorkflowPath startWorkflow(String workflowDefinitionId, Map<QName, Serializable> parameters)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(workflowDefinitionId);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
return component.startWorkflow(workflowDefinitionId, parameters);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#startWorkflowFromTemplate(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public WorkflowPath startWorkflowFromTemplate(NodeRef templateDefinition)
|
||||
{
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getActiveWorkflows(java.lang.String)
|
||||
*/
|
||||
public List<WorkflowInstance> getActiveWorkflows(String workflowDefinitionId)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(workflowDefinitionId);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
return component.getActiveWorkflows(workflowDefinitionId);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getWorkflowPaths(java.lang.String)
|
||||
*/
|
||||
public List<WorkflowPath> getWorkflowPaths(String workflowId)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(workflowId);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
return component.getWorkflowPaths(workflowId);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#cancelWorkflow(java.lang.String)
|
||||
*/
|
||||
public WorkflowInstance cancelWorkflow(String workflowId)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(workflowId);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
return component.cancelWorkflow(workflowId);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#signal(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public WorkflowPath signal(String pathId, String transition)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(pathId);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
return component.signal(pathId, transition);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getTasksForWorkflowPath(java.lang.String)
|
||||
*/
|
||||
public List<WorkflowTask> getTasksForWorkflowPath(String pathId)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(pathId);
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
return component.getTasksForWorkflowPath(pathId);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getAssignedTasks(java.lang.String, org.alfresco.service.cmr.workflow.WorkflowTaskState)
|
||||
*/
|
||||
public List<WorkflowTask> getAssignedTasks(String authority, WorkflowTaskState state)
|
||||
{
|
||||
List<WorkflowTask> tasks = new ArrayList<WorkflowTask>(10);
|
||||
String[] ids = registry.getTaskComponents();
|
||||
for (String id: ids)
|
||||
{
|
||||
TaskComponent component = registry.getTaskComponent(id);
|
||||
tasks.addAll(component.getAssignedTasks(authority, state));
|
||||
}
|
||||
return Collections.unmodifiableList(tasks);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getPooledTasks(java.lang.String)
|
||||
*/
|
||||
public List<WorkflowTask> getPooledTasks(String authority)
|
||||
{
|
||||
// TODO: Expand authorities to include associated groups (and parent groups)
|
||||
List<String> authorities = new ArrayList<String>();
|
||||
authorities.add(authority);
|
||||
|
||||
List<WorkflowTask> tasks = new ArrayList<WorkflowTask>(10);
|
||||
String[] ids = registry.getTaskComponents();
|
||||
for (String id: ids)
|
||||
{
|
||||
TaskComponent component = registry.getTaskComponent(id);
|
||||
tasks.addAll(component.getPooledTasks(authorities));
|
||||
}
|
||||
return Collections.unmodifiableList(tasks);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#updateTask(java.lang.String, java.util.Map, java.util.Map, java.util.Map)
|
||||
*/
|
||||
public WorkflowTask updateTask(String taskId, Map<QName, Serializable> properties, Map<QName, List<NodeRef>> add, Map<QName, List<NodeRef>> remove)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(taskId);
|
||||
TaskComponent component = getTaskComponent(engineId);
|
||||
return component.updateTask(taskId, properties, add, remove);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#endTask(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public WorkflowTask endTask(String taskId, String transition)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(taskId);
|
||||
TaskComponent component = getTaskComponent(engineId);
|
||||
return component.endTask(taskId, transition);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#getTaskById(java.lang.String)
|
||||
*/
|
||||
public WorkflowTask getTaskById(String taskId)
|
||||
{
|
||||
String engineId = BPMEngineRegistry.getEngineId(taskId);
|
||||
TaskComponent component = getTaskComponent(engineId);
|
||||
return component.getTaskById(taskId);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.workflow.WorkflowService#createPackage(java.lang.String, org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public NodeRef createPackage(NodeRef container)
|
||||
{
|
||||
return workflowPackageComponent.createPackage(container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Workflow Component registered against the specified BPM Engine Id
|
||||
*
|
||||
* @param engineId engine id
|
||||
*/
|
||||
private WorkflowComponent getWorkflowComponent(String engineId)
|
||||
{
|
||||
WorkflowComponent component = registry.getWorkflowComponent(engineId);
|
||||
if (component == null)
|
||||
{
|
||||
throw new WorkflowException("Workflow Component for engine id '" + engineId + "' is not registered");
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Task Component registered against the specified BPM Engine Id
|
||||
*
|
||||
* @param engineId engine id
|
||||
*/
|
||||
private TaskComponent getTaskComponent(String engineId)
|
||||
{
|
||||
TaskComponent component = registry.getTaskComponent(engineId);
|
||||
if (component == null)
|
||||
{
|
||||
throw new WorkflowException("Task Component for engine id '" + engineId + "' is not registered");
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
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.util.BaseSpringTest;
|
||||
|
||||
|
||||
/**
|
||||
* Workflow Service Implementation Tests
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class WorkflowServiceImplTest extends BaseSpringTest
|
||||
{
|
||||
WorkflowService workflowService;
|
||||
NodeService nodeService;
|
||||
|
||||
//@Override
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
workflowService = (WorkflowService)applicationContext.getBean(ServiceRegistry.WORKFLOW_SERVICE.getLocalName());
|
||||
nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName());
|
||||
}
|
||||
|
||||
public void testGetWorkflowDefinitions()
|
||||
{
|
||||
List<WorkflowDefinition> workflowDefs = workflowService.getDefinitions();
|
||||
assertNotNull(workflowDefs);
|
||||
assertTrue(workflowDefs.size() > 0);
|
||||
}
|
||||
|
||||
public void testStartWorkflow()
|
||||
{
|
||||
List<WorkflowDefinition> workflowDefs = workflowService.getDefinitions();
|
||||
assertNotNull(workflowDefs);
|
||||
assertTrue(workflowDefs.size() > 0);
|
||||
WorkflowDefinition workflowDef = workflowDefs.get(0);
|
||||
WorkflowPath path = workflowService.startWorkflow(workflowDef.id, null);
|
||||
assertNotNull(path);
|
||||
assertTrue(path.active);
|
||||
assertNotNull(path.node);
|
||||
assertNotNull(path.instance);
|
||||
assertEquals(workflowDef.id, path.instance.definition.id);
|
||||
}
|
||||
|
||||
public void testWorkflowPackage()
|
||||
{
|
||||
NodeRef nodeRef = workflowService.createPackage(null);
|
||||
assertNotNull(nodeRef);
|
||||
assertTrue(nodeService.hasAspect(nodeRef, WorkflowModel.ASPECT_WORKFLOW_PACKAGE));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* 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 java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ScriptService;
|
||||
import org.dom4j.Element;
|
||||
import org.jbpm.context.def.VariableAccess;
|
||||
import org.jbpm.context.exe.ContextInstance;
|
||||
import org.jbpm.graph.exe.ExecutionContext;
|
||||
import org.jbpm.graph.exe.Token;
|
||||
import org.jbpm.jpdl.xml.JpdlXmlReader;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* A jBPM Action Handler for executing Alfresco Script
|
||||
*
|
||||
* The configuration of this action is as follows:
|
||||
* <script language="javascript">
|
||||
* <expression>
|
||||
* the script to execute
|
||||
* </expression>
|
||||
* <variable name="watcha" access="write"/>
|
||||
* </script>
|
||||
*
|
||||
* It's exactly the same as jBPM's own script configuration.
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
||||
{
|
||||
private static final long serialVersionUID = -2908748080671212745L;
|
||||
|
||||
private static JpdlXmlReader jpdlReader = new JpdlXmlReader((InputSource)null);
|
||||
private ScriptService scriptService;
|
||||
private Element script;
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler#initialiseHandler(org.springframework.beans.factory.BeanFactory)
|
||||
*/
|
||||
@Override
|
||||
protected void initialiseHandler(BeanFactory factory)
|
||||
{
|
||||
scriptService = (ScriptService)factory.getBean(ServiceRegistry.SCRIPT_SERVICE.getLocalName());
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute(ExecutionContext executionContext) throws Exception
|
||||
{
|
||||
// extract action configuration
|
||||
String expression = null;
|
||||
List<VariableAccess> variableAccesses = null;
|
||||
|
||||
// is the script specified as text only, or as explicit expression, variable elements
|
||||
boolean isTextOnly = true;
|
||||
Iterator<Element> iter = script.elementIterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
Element element = iter.next();
|
||||
if (element.getNodeType() == Element.ELEMENT_NODE)
|
||||
{
|
||||
isTextOnly = false;
|
||||
}
|
||||
}
|
||||
|
||||
// extract script and variables
|
||||
if (isTextOnly)
|
||||
{
|
||||
expression = script.getTextTrim();
|
||||
}
|
||||
else
|
||||
{
|
||||
variableAccesses = jpdlReader.readVariableAccesses(script);
|
||||
expression = script.element("expression").getTextTrim();
|
||||
}
|
||||
|
||||
// construct script arguments and execute
|
||||
Map<String, Object> inputMap = createInputMap(executionContext, variableAccesses);
|
||||
Object result = scriptService.executeScriptString(expression, inputMap);
|
||||
|
||||
// map script return variable to process context
|
||||
VariableAccess returnVariable = getWritableVariable(variableAccesses);
|
||||
if (returnVariable != null)
|
||||
{
|
||||
ContextInstance contextInstance = executionContext.getContextInstance();
|
||||
Token token = executionContext.getToken();
|
||||
contextInstance.setVariable(returnVariable.getVariableName(), result, token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct map of arguments to pass to script
|
||||
*
|
||||
* Based on the <variable> elements of the action configuration.
|
||||
*
|
||||
* @param executionContext the execution context
|
||||
* @param variableAccesses the variable configuration
|
||||
* @return the map of script arguments
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> createInputMap(ExecutionContext executionContext, List<VariableAccess> variableAccesses)
|
||||
{
|
||||
Map<String, Object> inputMap = new HashMap<String, Object>();
|
||||
|
||||
// initialise process variables
|
||||
Token token = executionContext.getToken();
|
||||
inputMap.put("executionContext", executionContext);
|
||||
inputMap.put("token", token);
|
||||
if (executionContext.getNode() != null)
|
||||
{
|
||||
inputMap.put("node", executionContext.getNode());
|
||||
}
|
||||
if (executionContext.getTask() != null)
|
||||
{
|
||||
inputMap.put("task", executionContext.getTask());
|
||||
}
|
||||
if (executionContext.getTaskInstance() != null)
|
||||
{
|
||||
inputMap.put("taskInstance", executionContext.getTaskInstance());
|
||||
}
|
||||
|
||||
// if no readable variableInstances are specified,
|
||||
ContextInstance contextInstance = executionContext.getContextInstance();
|
||||
if (!hasReadableVariable(variableAccesses))
|
||||
{
|
||||
// copy all the variableInstances of the context into the interpreter
|
||||
Map<String, Object> variables = contextInstance.getVariables(token);
|
||||
if (variables != null)
|
||||
{
|
||||
for (Map.Entry entry : variables.entrySet())
|
||||
{
|
||||
String variableName = (String) entry.getKey();
|
||||
Object variableValue = entry.getValue();
|
||||
inputMap.put(variableName, variableValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy the specified variableInstances into the interpreterz
|
||||
for (VariableAccess variableAccess : variableAccesses)
|
||||
{
|
||||
if (variableAccess.isReadable())
|
||||
{
|
||||
String variableName = variableAccess.getVariableName();
|
||||
String mappedName = variableAccess.getMappedName();
|
||||
Object variableValue = contextInstance.getVariable(variableName, token);
|
||||
inputMap.put(mappedName, variableValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inputMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if there are variables to read from the process context
|
||||
*
|
||||
* @param variableAccesses the variables configuration
|
||||
* @return true => there are variables to read
|
||||
*/
|
||||
private boolean hasReadableVariable(List<VariableAccess> variableAccesses)
|
||||
{
|
||||
if (variableAccesses != null)
|
||||
{
|
||||
for (VariableAccess variableAccess : variableAccesses)
|
||||
{
|
||||
if (variableAccess.isReadable())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if there is a variable to write back to the process context
|
||||
*
|
||||
* @param variableAccesses the variables configuration
|
||||
* @return true => there is a variable to write
|
||||
*/
|
||||
private VariableAccess getWritableVariable(List<VariableAccess> variableAccesses)
|
||||
{
|
||||
if (variableAccesses != null)
|
||||
{
|
||||
for (VariableAccess variableAccess : variableAccesses)
|
||||
{
|
||||
if (variableAccess.isWritable())
|
||||
{
|
||||
return variableAccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
1636
source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java
Normal file
1636
source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java
Normal file
File diff suppressed because it is too large
Load Diff
469
source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java
Normal file
469
source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java
Normal file
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* 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 java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.i18n.I18NUtil;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.workflow.BPMEngineRegistry;
|
||||
import org.alfresco.repo.workflow.TaskComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
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.WorkflowDeployment;
|
||||
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.WorkflowTask;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
|
||||
/**
|
||||
* JBPM Engine Tests
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class JBPMEngineTest extends BaseSpringTest
|
||||
{
|
||||
AuthenticationComponent authenticationComponent;
|
||||
NodeService nodeService;
|
||||
WorkflowComponent workflowComponent;
|
||||
TaskComponent taskComponent;
|
||||
WorkflowDefinition testWorkflowDef;
|
||||
NodeRef testNodeRef;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
// run as system
|
||||
authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent");
|
||||
authenticationComponent.setCurrentUser("admin");
|
||||
|
||||
BPMEngineRegistry registry = (BPMEngineRegistry)applicationContext.getBean("bpm_engineRegistry");
|
||||
workflowComponent = registry.getWorkflowComponent("jbpm");
|
||||
taskComponent = registry.getTaskComponent("jbpm");
|
||||
|
||||
// deploy test process messages
|
||||
I18NUtil.registerResourceBundle("org/alfresco/repo/workflow/jbpm/test-messages");
|
||||
|
||||
// deploy test process definition
|
||||
ClassPathResource processDef = new ClassPathResource("org/alfresco/repo/workflow/jbpm/test_processdefinition.xml");
|
||||
assertFalse(workflowComponent.isDefinitionDeployed(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML));
|
||||
WorkflowDeployment deployment = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML);
|
||||
testWorkflowDef = deployment.definition;
|
||||
assertNotNull(testWorkflowDef);
|
||||
assertEquals("test", testWorkflowDef.name);
|
||||
assertEquals("1", testWorkflowDef.version);
|
||||
assertTrue(workflowComponent.isDefinitionDeployed(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML));
|
||||
|
||||
// get valid node ref
|
||||
nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName());
|
||||
testNodeRef = nodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "spacesStore"));
|
||||
nodeService.setProperty(testNodeRef, ContentModel.PROP_CREATED, new Date());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onTearDownInTransaction()
|
||||
{
|
||||
authenticationComponent.clearCurrentSecurityContext();
|
||||
}
|
||||
|
||||
|
||||
public void testGetWorkflowDefinitions()
|
||||
{
|
||||
List<WorkflowDefinition> workflowDefs = workflowComponent.getDefinitions();
|
||||
assertNotNull(workflowDefs);
|
||||
assertTrue(workflowDefs.size() > 0);
|
||||
}
|
||||
|
||||
|
||||
public void testDeployWorkflow() throws Exception
|
||||
{
|
||||
ClassPathResource processDef = new ClassPathResource("org/alfresco/repo/workflow/jbpm/test_processdefinition.xml");
|
||||
WorkflowDeployment deployment = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML);
|
||||
testWorkflowDef = deployment.definition;
|
||||
assertNotNull(testWorkflowDef);
|
||||
assertEquals("test", testWorkflowDef.name);
|
||||
assertEquals("2", testWorkflowDef.version);
|
||||
}
|
||||
|
||||
|
||||
public void testStartWorkflow()
|
||||
{
|
||||
try
|
||||
{
|
||||
@SuppressWarnings("unused") WorkflowPath path = workflowComponent.startWorkflow("norfolknchance", null);
|
||||
fail("Failed to catch invalid definition id");
|
||||
}
|
||||
catch(WorkflowException e)
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: Determine why process definition is loaded, even though it doesn't exist
|
||||
// try
|
||||
// {
|
||||
// @SuppressWarnings("unused") WorkflowPosition pos = workflowComponent.startProcess("1000", null);
|
||||
// fail("Failed to catch workflow definition id that does not exist");
|
||||
// }
|
||||
// catch(WorkflowException e)
|
||||
// {
|
||||
// }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
public void testStartWorkflowParameters()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
|
||||
Map<QName, Serializable> params = new HashMap<QName, Serializable>();
|
||||
params.put(WorkflowModel.PROP_TASK_ID, 3); // protected - shouldn't be written
|
||||
params.put(WorkflowModel.PROP_DUE_DATE, new Date()); // task instance field
|
||||
params.put(WorkflowModel.PROP_PRIORITY, 1); // task instance field
|
||||
params.put(WorkflowModel.PROP_PERCENT_COMPLETE, 10); // context variable
|
||||
params.put(QName.createQName("", "Message"), "Hello World"); // context variable outside of task definition
|
||||
params.put(QName.createQName("", "Array"), new String[] { "one", "two" }); // context variable outside of task definition
|
||||
params.put(QName.createQName("", "NodeRef"), new NodeRef("workspace://1/1001")); // context variable outside of task definition
|
||||
params.put(ContentModel.PROP_OWNER, "admin"); // task assignment
|
||||
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, params);
|
||||
assertNotNull(path);
|
||||
assertTrue(path.id.endsWith("-@"));
|
||||
assertNotNull(path.node);
|
||||
assertNotNull(path.instance);
|
||||
assertEquals(workflowDef.id, path.instance.definition.id);
|
||||
List<WorkflowTask> tasks1 = workflowComponent.getTasksForWorkflowPath(path.id);
|
||||
assertNotNull(tasks1);
|
||||
assertEquals(1, tasks1.size());
|
||||
|
||||
WorkflowTask task = tasks1.get(0);
|
||||
assertTrue(task.properties.containsKey(WorkflowModel.PROP_TASK_ID));
|
||||
assertTrue(task.properties.containsKey(WorkflowModel.PROP_DUE_DATE));
|
||||
assertTrue(task.properties.containsKey(WorkflowModel.PROP_PRIORITY));
|
||||
assertTrue(task.properties.containsKey(WorkflowModel.PROP_PERCENT_COMPLETE));
|
||||
assertTrue(task.properties.containsKey(ContentModel.PROP_OWNER));
|
||||
|
||||
NodeRef initiator = path.instance.initiator;
|
||||
String initiatorUsername = (String)nodeService.getProperty(initiator, ContentModel.PROP_USERNAME);
|
||||
assertEquals("admin", initiatorUsername);
|
||||
}
|
||||
|
||||
|
||||
public void testUpdateTask()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
|
||||
Map<QName, Serializable> params = new HashMap<QName, Serializable>();
|
||||
params.put(WorkflowModel.PROP_TASK_ID, 3); // protected - shouldn't be written
|
||||
params.put(WorkflowModel.PROP_DUE_DATE, new Date()); // task instance field
|
||||
params.put(WorkflowModel.PROP_PRIORITY, 1); // task instance field
|
||||
params.put(WorkflowModel.PROP_PERCENT_COMPLETE, 10); // context variable
|
||||
params.put(QName.createQName("", "Message"), "Hello World"); // context variable outside of task definition
|
||||
params.put(QName.createQName("", "Array"), new String[] { "one", "two" }); // context variable outside of task definition
|
||||
params.put(QName.createQName("", "NodeRef"), new NodeRef("workspace://1/1001")); // context variable outside of task definition
|
||||
params.put(ContentModel.PROP_OWNER, "admin"); // task assignment
|
||||
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, params);
|
||||
assertNotNull(path);
|
||||
assertTrue(path.id.endsWith("-@"));
|
||||
assertNotNull(path.node);
|
||||
assertNotNull(path.instance);
|
||||
assertEquals(workflowDef.id, path.instance.definition.id);
|
||||
List<WorkflowTask> tasks1 = workflowComponent.getTasksForWorkflowPath(path.id);
|
||||
assertNotNull(tasks1);
|
||||
assertEquals(1, tasks1.size());
|
||||
|
||||
WorkflowTask task = tasks1.get(0);
|
||||
assertTrue(task.properties.containsKey(WorkflowModel.PROP_TASK_ID));
|
||||
assertTrue(task.properties.containsKey(WorkflowModel.PROP_DUE_DATE));
|
||||
assertTrue(task.properties.containsKey(WorkflowModel.PROP_PRIORITY));
|
||||
assertTrue(task.properties.containsKey(WorkflowModel.PROP_PERCENT_COMPLETE));
|
||||
assertTrue(task.properties.containsKey(ContentModel.PROP_OWNER));
|
||||
|
||||
// update with null parameters
|
||||
try
|
||||
{
|
||||
WorkflowTask taskU1 = taskComponent.updateTask(task.id, null, null, null);
|
||||
assertNotNull(taskU1);
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
fail("Task update failed with null parameters");
|
||||
}
|
||||
|
||||
// update property value
|
||||
Map<QName, Serializable> updateProperties2 = new HashMap<QName, Serializable>();
|
||||
updateProperties2.put(WorkflowModel.PROP_PERCENT_COMPLETE, 100);
|
||||
WorkflowTask taskU2 = taskComponent.updateTask(task.id, updateProperties2, null, null);
|
||||
assertEquals(100, taskU2.properties.get(WorkflowModel.PROP_PERCENT_COMPLETE));
|
||||
|
||||
// add to assocation
|
||||
QName assocName = QName.createQName("", "TestAssoc");
|
||||
List<NodeRef> toAdd = new ArrayList<NodeRef>();
|
||||
toAdd.add(new NodeRef("workspace://1/1001"));
|
||||
toAdd.add(new NodeRef("workspace://1/1002"));
|
||||
toAdd.add(new NodeRef("workspace://1/1003"));
|
||||
Map<QName, List<NodeRef>> addAssocs = new HashMap<QName, List<NodeRef>>();
|
||||
addAssocs.put(assocName, toAdd);
|
||||
WorkflowTask taskU3 = taskComponent.updateTask(task.id, null, addAssocs, null);
|
||||
assertNotNull(taskU3.properties.get(assocName));
|
||||
assertEquals(3, ((List<NodeRef>)taskU3.properties.get(assocName)).size());
|
||||
|
||||
// add to assocation again
|
||||
List<NodeRef> toAddAgain = new ArrayList<NodeRef>();
|
||||
toAddAgain.add(new NodeRef("workspace://1/1004"));
|
||||
toAddAgain.add(new NodeRef("workspace://1/1005"));
|
||||
Map<QName, List<NodeRef>> addAssocsAgain = new HashMap<QName, List<NodeRef>>();
|
||||
addAssocsAgain.put(assocName, toAddAgain);
|
||||
WorkflowTask taskU4 = taskComponent.updateTask(task.id, null, addAssocsAgain, null);
|
||||
assertNotNull(taskU4.properties.get(assocName));
|
||||
assertEquals(5, ((List<NodeRef>)taskU4.properties.get(assocName)).size());
|
||||
|
||||
// remove assocation
|
||||
List<NodeRef> toRemove = new ArrayList<NodeRef>();
|
||||
toRemove.add(new NodeRef("workspace://1/1002"));
|
||||
toRemove.add(new NodeRef("workspace://1/1003"));
|
||||
Map<QName, List<NodeRef>> removeAssocs = new HashMap<QName, List<NodeRef>>();
|
||||
removeAssocs.put(assocName, toRemove);
|
||||
WorkflowTask taskU5 = taskComponent.updateTask(task.id, null, null, removeAssocs);
|
||||
assertNotNull(taskU5.properties.get(assocName));
|
||||
assertEquals(3, ((List<NodeRef>)taskU5.properties.get(assocName)).size());
|
||||
}
|
||||
|
||||
|
||||
public void testGetWorkflowInstances()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
workflowComponent.startWorkflow(workflowDef.id, null);
|
||||
workflowComponent.startWorkflow(workflowDef.id, null);
|
||||
List<WorkflowInstance> instances = workflowComponent.getActiveWorkflows(workflowDef.id);
|
||||
assertNotNull(instances);
|
||||
assertEquals(2, instances.size());
|
||||
for (WorkflowInstance instance : instances)
|
||||
{
|
||||
assertEquals(workflowDef.id, instance.definition.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testGetPositions()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
workflowComponent.startWorkflow(workflowDef.id, null);
|
||||
List<WorkflowInstance> instances = workflowComponent.getActiveWorkflows(workflowDef.id);
|
||||
assertNotNull(instances);
|
||||
assertEquals(1, instances.size());
|
||||
List<WorkflowPath> paths = workflowComponent.getWorkflowPaths(instances.get(0).id);
|
||||
assertNotNull(paths);
|
||||
assertEquals(1, paths.size());
|
||||
assertEquals(instances.get(0).id, paths.get(0).instance.id);
|
||||
assertTrue(paths.get(0).id.endsWith("-@"));
|
||||
}
|
||||
|
||||
|
||||
public void testCancelWorkflowInstance()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
workflowComponent.startWorkflow(workflowDef.id, null);
|
||||
List<WorkflowInstance> instances1 = workflowComponent.getActiveWorkflows(workflowDef.id);
|
||||
assertNotNull(instances1);
|
||||
assertEquals(1, instances1.size());
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
public void testSignal()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, null);
|
||||
assertNotNull(path);
|
||||
WorkflowPath updatedPath = workflowComponent.signal(path.id, path.node.transitions[1].id);
|
||||
assertNotNull(updatedPath);
|
||||
}
|
||||
|
||||
|
||||
public void testGetAssignedTasks()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), "admin");
|
||||
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());
|
||||
WorkflowTask updatedTask = taskComponent.endTask(tasks.get(0).id, path.node.transitions[0].id);
|
||||
assertNotNull(updatedTask);
|
||||
List<WorkflowTask> completedTasks = taskComponent.getAssignedTasks("admin", WorkflowTaskState.COMPLETED);
|
||||
assertNotNull(completedTasks);
|
||||
completedTasks = filterTasksByWorkflowInstance(completedTasks, path.instance.id);
|
||||
assertEquals(1, completedTasks.size());
|
||||
List<WorkflowTask> assignedTasks = taskComponent.getAssignedTasks("admin", WorkflowTaskState.IN_PROGRESS);
|
||||
assertNotNull(assignedTasks);
|
||||
assignedTasks = filterTasksByWorkflowInstance(assignedTasks, path.instance.id);
|
||||
assertEquals(1, assignedTasks.size());
|
||||
assertEquals("review", assignedTasks.get(0).name);
|
||||
}
|
||||
|
||||
|
||||
public void testEndTask()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), "admin");
|
||||
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());
|
||||
assertEquals(WorkflowTaskState.IN_PROGRESS, tasks1.get(0).state);
|
||||
WorkflowTask updatedTask = taskComponent.endTask(tasks1.get(0).id, null);
|
||||
assertNotNull(updatedTask);
|
||||
assertEquals(WorkflowTaskState.COMPLETED, updatedTask.state);
|
||||
List<WorkflowTask> completedTasks = taskComponent.getAssignedTasks("admin", WorkflowTaskState.COMPLETED);
|
||||
assertNotNull(completedTasks);
|
||||
completedTasks = filterTasksByWorkflowInstance(completedTasks, path.instance.id);
|
||||
assertEquals(1, completedTasks.size());
|
||||
assertEquals(WorkflowTaskState.COMPLETED, completedTasks.get(0).state);
|
||||
}
|
||||
|
||||
|
||||
public void testGetTask()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), "admin");
|
||||
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());
|
||||
WorkflowTask getTask = taskComponent.getTaskById(tasks1.get(0).id);
|
||||
assertNotNull(getTask);
|
||||
assertEquals(getTask.id, tasks1.get(0).id);
|
||||
}
|
||||
|
||||
|
||||
public void testNodeRef()
|
||||
{
|
||||
WorkflowDefinition workflowDef = getTestDefinition();
|
||||
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), "admin");
|
||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "testNode"), testNodeRef);
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
||||
assertNotNull(path);
|
||||
List<WorkflowTask> tasks1 = workflowComponent.getTasksForWorkflowPath(path.id);
|
||||
assertNotNull(tasks1);
|
||||
assertEquals(1, tasks1.size());
|
||||
assertEquals(WorkflowTaskState.IN_PROGRESS, tasks1.get(0).state);
|
||||
WorkflowTask updatedTask = taskComponent.endTask(tasks1.get(0).id, null);
|
||||
assertNotNull(updatedTask);
|
||||
}
|
||||
|
||||
|
||||
public void testScript()
|
||||
throws IOException
|
||||
{
|
||||
// deploy test script definition
|
||||
ClassPathResource processDef = new ClassPathResource("org/alfresco/repo/workflow/jbpm/test_script.xml");
|
||||
assertFalse(workflowComponent.isDefinitionDeployed(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML));
|
||||
WorkflowDeployment deployment = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML);
|
||||
assertNotNull(deployment);
|
||||
|
||||
WorkflowDefinition workflowDef = deployment.definition;
|
||||
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "testNode"), testNodeRef);
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
||||
assertNotNull(path);
|
||||
List<WorkflowTask> tasks1 = workflowComponent.getTasksForWorkflowPath(path.id);
|
||||
assertNotNull(tasks1);
|
||||
assertEquals(1, tasks1.size());
|
||||
assertEquals(WorkflowTaskState.IN_PROGRESS, tasks1.get(0).state);
|
||||
WorkflowTask updatedTask = taskComponent.endTask(tasks1.get(0).id, null);
|
||||
assertNotNull(updatedTask);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Locate the Test Workflow Definition
|
||||
*
|
||||
* @return workflow definition
|
||||
*/
|
||||
private WorkflowDefinition getTestDefinition()
|
||||
{
|
||||
return testWorkflowDef;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filter task list by workflow instance
|
||||
*
|
||||
* @param tasks
|
||||
* @param processInstanceId
|
||||
* @return
|
||||
*/
|
||||
private List<WorkflowTask> filterTasksByWorkflowInstance(List<WorkflowTask> tasks, String workflowInstanceId)
|
||||
{
|
||||
List<WorkflowTask> filteredTasks = new ArrayList<WorkflowTask>();
|
||||
for (WorkflowTask task : tasks)
|
||||
{
|
||||
if (task.path.instance.id.equals(workflowInstanceId))
|
||||
{
|
||||
filteredTasks.add(task);
|
||||
}
|
||||
}
|
||||
return filteredTasks;
|
||||
}
|
||||
|
||||
}
|
96
source/java/org/alfresco/repo/workflow/jbpm/JBPMNode.java
Normal file
96
source/java/org/alfresco/repo/workflow/jbpm/JBPMNode.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
|
||||
/**
|
||||
* Scriptable Node suitable for JBPM Beanshell access
|
||||
*
|
||||
* TODO: This implementation derives from the JavaScript Alfresco Node. At
|
||||
* some point we should look to having a script-independent node with various
|
||||
* script-specific sub-types (and value conversions).
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class JBPMNode extends org.alfresco.repo.jscript.Node
|
||||
{
|
||||
private static final long serialVersionUID = -826970280203254365L;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param nodeRef node reference
|
||||
* @param services services
|
||||
*/
|
||||
public JBPMNode(NodeRef nodeRef, ServiceRegistry services)
|
||||
{
|
||||
super(nodeRef, services, null);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.jscript.Node#createValueConverter()
|
||||
*/
|
||||
@Override
|
||||
protected NodeValueConverter createValueConverter()
|
||||
{
|
||||
return new JBPMNodeConverter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Value converter for beanshell.
|
||||
*/
|
||||
private class JBPMNodeConverter extends org.alfresco.repo.jscript.Node.NodeValueConverter
|
||||
{
|
||||
@Override
|
||||
public Serializable convertValueForRepo(Serializable value)
|
||||
{
|
||||
if (value instanceof Date)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.convertValueForRepo(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable convertValueForScript(ServiceRegistry services, Scriptable scope, QName qname, Serializable value)
|
||||
{
|
||||
if (value instanceof NodeRef)
|
||||
{
|
||||
return new JBPMNode(((NodeRef)value), services);
|
||||
}
|
||||
else if (value instanceof Date)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.convertValueForScript(services, scope, qname, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
package org.alfresco.repo.workflow.jbpm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class JBPMNodeList extends ArrayList<JBPMNode>
|
||||
{
|
||||
private static final long serialVersionUID = 1376915749912156471L;
|
||||
}
|
@@ -41,9 +41,9 @@ public class JBPMSpringTest extends BaseSpringTest
|
||||
|
||||
|
||||
//@Override
|
||||
protected void xonSetUpInTransaction() throws Exception
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
jbpmTemplate = (JbpmTemplate)applicationContext.getBean("jbpm.template");
|
||||
jbpmTemplate = (JbpmTemplate)applicationContext.getBean("jbpm_template");
|
||||
descriptorService = (DescriptorService)applicationContext.getBean("DescriptorService");
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class JBPMSpringTest extends BaseSpringTest
|
||||
{
|
||||
}
|
||||
|
||||
public void xtestHelloWorld()
|
||||
public void testHelloWorld()
|
||||
throws Exception
|
||||
{
|
||||
// Between the 3 method calls below, all data is passed via the
|
||||
@@ -74,21 +74,21 @@ public class JBPMSpringTest extends BaseSpringTest
|
||||
theProcessInstanceContinuesWhenAnAsyncMessageIsReceived();
|
||||
}
|
||||
|
||||
public void xtestStep0()
|
||||
public void testStep0()
|
||||
throws Exception
|
||||
{
|
||||
deployProcessDefinition();
|
||||
setComplete();
|
||||
}
|
||||
|
||||
public void xtestStep1()
|
||||
public void testStep1()
|
||||
throws Exception
|
||||
{
|
||||
processInstanceIsCreatedWhenUserSubmitsWebappForm();
|
||||
setComplete();
|
||||
}
|
||||
|
||||
public void xtestStep2()
|
||||
public void testStep2()
|
||||
throws Exception
|
||||
{
|
||||
theProcessInstanceContinuesWhenAnAsyncMessageIsReceived();
|
||||
|
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.jbpm.context.exe.Converter;
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
import org.springframework.beans.factory.access.BeanFactoryReference;
|
||||
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
|
||||
|
||||
|
||||
/**
|
||||
* jBPM Converter for transforming Alfresco Node to string and back
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class NodeConverter implements Converter
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static BeanFactoryLocator jbpmFactoryLocator = new JbpmFactoryLocator();
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jbpm.context.exe.Converter#supports(java.lang.Object)
|
||||
*/
|
||||
public boolean supports(Object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return (value.getClass() == JBPMNode.class);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jbpm.context.exe.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
public Object convert(Object o)
|
||||
{
|
||||
Object converted = null;
|
||||
if (o != null)
|
||||
{
|
||||
converted = ((JBPMNode)o).getNodeRef().toString();
|
||||
}
|
||||
return converted;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jbpm.context.exe.Converter#revert(java.lang.Object)
|
||||
*/
|
||||
public Object revert(Object o)
|
||||
{
|
||||
Object reverted = null;
|
||||
if (o != null)
|
||||
{
|
||||
BeanFactoryReference factory = jbpmFactoryLocator.useBeanFactory(null);
|
||||
ServiceRegistry serviceRegistry = (ServiceRegistry)factory.getFactory().getBean(ServiceRegistry.SERVICE_REGISTRY);
|
||||
reverted = new JBPMNode(new NodeRef((String)o), serviceRegistry);
|
||||
}
|
||||
return reverted;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.jbpm.context.exe.converter.SerializableToByteArrayConverter;
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
import org.springframework.beans.factory.access.BeanFactoryReference;
|
||||
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
|
||||
|
||||
|
||||
/**
|
||||
* jBPM Converter for transforming Alfresco Node to string and back
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class NodeListConverter extends SerializableToByteArrayConverter
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static BeanFactoryLocator jbpmFactoryLocator = new JbpmFactoryLocator();
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jbpm.context.exe.Converter#supports(java.lang.Object)
|
||||
*/
|
||||
public boolean supports(Object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return (value.getClass() == JBPMNodeList.class);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jbpm.context.exe.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
public Object convert(Object o)
|
||||
{
|
||||
Object converted = null;
|
||||
if (o != null)
|
||||
{
|
||||
JBPMNodeList nodes = (JBPMNodeList)o;
|
||||
List<NodeRef> values = new ArrayList<NodeRef>(nodes.size());
|
||||
for (JBPMNode node : nodes)
|
||||
{
|
||||
values.add(node.getNodeRef());
|
||||
}
|
||||
converted = super.convert(values);
|
||||
}
|
||||
return converted;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jbpm.context.exe.Converter#revert(java.lang.Object)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object revert(Object o)
|
||||
{
|
||||
Object reverted = null;
|
||||
if (o != null)
|
||||
{
|
||||
List<NodeRef> nodeRefs = (List<NodeRef>)super.revert(o);
|
||||
BeanFactoryReference factory = jbpmFactoryLocator.useBeanFactory(null);
|
||||
ServiceRegistry serviceRegistry = (ServiceRegistry)factory.getFactory().getBean(ServiceRegistry.SERVICE_REGISTRY);
|
||||
|
||||
JBPMNodeList nodes = new JBPMNodeList();
|
||||
for (NodeRef nodeRef : nodeRefs)
|
||||
{
|
||||
nodes.add(new JBPMNode(nodeRef, serviceRegistry));
|
||||
}
|
||||
reverted = nodes;
|
||||
}
|
||||
return reverted;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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 java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.workflow.BPMEngineRegistry;
|
||||
import org.alfresco.repo.workflow.TaskComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
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.security.PersonService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDeployment;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowPath;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
|
||||
/**
|
||||
* JBPM Engine Tests
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class NodeListConverterTest extends BaseSpringTest
|
||||
{
|
||||
AuthenticationComponent authenticationComponent;
|
||||
PersonService personService;
|
||||
WorkflowComponent workflowComponent;
|
||||
TaskComponent taskComponent;
|
||||
WorkflowDefinition testWorkflowDef;
|
||||
NodeRef testNodeRef;
|
||||
|
||||
private static String taskId = null;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
personService = (PersonService)applicationContext.getBean("personService");
|
||||
BPMEngineRegistry registry = (BPMEngineRegistry)applicationContext.getBean("bpm_engineRegistry");
|
||||
workflowComponent = registry.getWorkflowComponent("jbpm");
|
||||
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");
|
||||
WorkflowDeployment deployment = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML);
|
||||
testWorkflowDef = deployment.definition;
|
||||
assertNotNull(testWorkflowDef);
|
||||
|
||||
// run as system
|
||||
authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent");
|
||||
authenticationComponent.setSystemUserAsCurrentUser();
|
||||
|
||||
// get valid node ref
|
||||
NodeService nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName());
|
||||
testNodeRef = nodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "spacesStore"));
|
||||
}
|
||||
|
||||
|
||||
public void testStep1Start()
|
||||
{
|
||||
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);
|
||||
NodeRef reviewer = personService.getPerson("admin");
|
||||
params.put(QName.createQName("http://www.alfresco.org/model/workflow/1.0", "reviewer"), reviewer);
|
||||
|
||||
WorkflowPath path = workflowComponent.startWorkflow(testWorkflowDef.id, params);
|
||||
assertNotNull(path);
|
||||
List<WorkflowTask> tasks1 = workflowComponent.getTasksForWorkflowPath(path.id);
|
||||
assertNotNull(tasks1);
|
||||
assertEquals(1, tasks1.size());
|
||||
|
||||
setComplete();
|
||||
taskId = tasks1.get(0).id;
|
||||
}
|
||||
|
||||
|
||||
public void testSetNodeRefList()
|
||||
{
|
||||
List<NodeRef> nodeRefs = new ArrayList<NodeRef>();
|
||||
nodeRefs.add(testNodeRef);
|
||||
nodeRefs.add(testNodeRef);
|
||||
Map<QName, Serializable> params = new HashMap<QName, Serializable>();
|
||||
params.put(WorkflowModel.PROP_COMPLETED_ITEMS, (Serializable)nodeRefs);
|
||||
|
||||
WorkflowTask task = taskComponent.getTaskById(taskId);
|
||||
assertNull(task.properties.get(WorkflowModel.PROP_COMPLETED_ITEMS));
|
||||
|
||||
WorkflowTask updatedTask = taskComponent.updateTask(taskId, params, null, null);
|
||||
assertNotNull(updatedTask);
|
||||
assertTrue(updatedTask.properties.containsKey(WorkflowModel.PROP_COMPLETED_ITEMS));
|
||||
assertEquals(2, ((List)updatedTask.properties.get(WorkflowModel.PROP_COMPLETED_ITEMS)).size());
|
||||
|
||||
setComplete();
|
||||
}
|
||||
|
||||
|
||||
public void testUpdateNodeRefList()
|
||||
{
|
||||
List<NodeRef> nodeRefs = new ArrayList<NodeRef>();
|
||||
// nodeRefs.add(testNodeRef);
|
||||
Map<QName, Serializable> params = new HashMap<QName, Serializable>();
|
||||
params.put(WorkflowModel.PROP_COMPLETED_ITEMS, (Serializable)nodeRefs);
|
||||
|
||||
// WorkflowTask task = taskComponent.getTaskById(taskId);
|
||||
// assertNotNull(task);
|
||||
// assertTrue(task.properties.containsKey(WorkflowModel.PROP_COMPLETED_ITEMS));
|
||||
// assertEquals(2, ((List)task.properties.get(WorkflowModel.PROP_COMPLETED_ITEMS)).size());
|
||||
|
||||
WorkflowTask updatedTask = taskComponent.updateTask(taskId, params, null, null);
|
||||
assertNotNull(updatedTask);
|
||||
assertTrue(updatedTask.properties.containsKey(WorkflowModel.PROP_COMPLETED_ITEMS));
|
||||
assertEquals(0, ((List)updatedTask.properties.get(WorkflowModel.PROP_COMPLETED_ITEMS)).size());
|
||||
|
||||
setComplete();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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 java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.workflow.BPMEngineRegistry;
|
||||
import org.alfresco.repo.workflow.TaskComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
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.security.PersonService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDeployment;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowPath;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
|
||||
/**
|
||||
* Review and Approve workflow specific Tests
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class ReviewAndApproveTest extends BaseSpringTest
|
||||
{
|
||||
AuthenticationComponent authenticationComponent;
|
||||
PersonService personService;
|
||||
WorkflowComponent workflowComponent;
|
||||
TaskComponent taskComponent;
|
||||
WorkflowDefinition testWorkflowDef;
|
||||
NodeRef testNodeRef;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
personService = (PersonService)applicationContext.getBean("personService");
|
||||
BPMEngineRegistry registry = (BPMEngineRegistry)applicationContext.getBean("bpm_engineRegistry");
|
||||
workflowComponent = registry.getWorkflowComponent("jbpm");
|
||||
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");
|
||||
WorkflowDeployment deployment = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML);
|
||||
testWorkflowDef = deployment.definition;
|
||||
assertNotNull(testWorkflowDef);
|
||||
|
||||
// run as system
|
||||
authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent");
|
||||
authenticationComponent.setSystemUserAsCurrentUser();
|
||||
|
||||
// get valid node ref
|
||||
NodeService nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName());
|
||||
testNodeRef = nodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "spacesStore"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTearDownInTransaction()
|
||||
{
|
||||
authenticationComponent.clearCurrentSecurityContext();
|
||||
}
|
||||
|
||||
|
||||
public void testSubmitForReview()
|
||||
{
|
||||
WorkflowDefinition workflowDef = testWorkflowDef;
|
||||
|
||||
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);
|
||||
NodeRef reviewer = personService.getPerson("admin");
|
||||
params.put(QName.createQName("http://www.alfresco.org/model/workflow/1.0", "reviewer"), reviewer);
|
||||
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, params);
|
||||
assertNotNull(path);
|
||||
List<WorkflowTask> tasks1 = workflowComponent.getTasksForWorkflowPath(path.id);
|
||||
assertNotNull(tasks1);
|
||||
assertEquals(1, tasks1.size());
|
||||
|
||||
WorkflowTask task = tasks1.get(0);
|
||||
assertTrue(task.properties.containsKey(WorkflowModel.ASSOC_PACKAGE));
|
||||
WorkflowTask endedTask = taskComponent.endTask(task.id, null);
|
||||
assertNotNull(endedTask);
|
||||
assertTrue(endedTask.properties.containsKey(WorkflowModel.PROP_OUTCOME));
|
||||
assertEquals("", endedTask.properties.get(WorkflowModel.PROP_OUTCOME));
|
||||
|
||||
List<WorkflowTask> assignedTasks = taskComponent.getAssignedTasks("admin", WorkflowTaskState.IN_PROGRESS);
|
||||
assertNotNull(assignedTasks);
|
||||
assignedTasks = filterTasksByWorkflowInstance(assignedTasks, path.instance.id);
|
||||
|
||||
assertEquals(testNodeRef, assignedTasks.get(0).properties.get(WorkflowModel.ASSOC_PACKAGE));
|
||||
assertEquals(reviewDueDate, assignedTasks.get(0).properties.get(WorkflowModel.PROP_DUE_DATE));
|
||||
}
|
||||
|
||||
public void testCompletedItems()
|
||||
{
|
||||
WorkflowDefinition workflowDef = testWorkflowDef;
|
||||
|
||||
List<NodeRef> nodeRefs = new ArrayList<NodeRef>();
|
||||
nodeRefs.add(testNodeRef);
|
||||
nodeRefs.add(testNodeRef);
|
||||
|
||||
Map<QName, Serializable> params = new HashMap<QName, Serializable>();
|
||||
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);
|
||||
NodeRef reviewer = personService.getPerson("admin");
|
||||
params.put(QName.createQName("http://www.alfresco.org/model/workflow/1.0", "reviewer"), reviewer);
|
||||
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, params);
|
||||
assertNotNull(path);
|
||||
List<WorkflowTask> tasks1 = workflowComponent.getTasksForWorkflowPath(path.id);
|
||||
assertNotNull(tasks1);
|
||||
assertEquals(1, tasks1.size());
|
||||
|
||||
WorkflowTask task = tasks1.get(0);
|
||||
assertTrue(task.properties.containsKey(WorkflowModel.PROP_COMPLETED_ITEMS));
|
||||
assertEquals(2, ((List)task.properties.get(WorkflowModel.PROP_COMPLETED_ITEMS)).size());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filter task list by workflow instance
|
||||
*
|
||||
* @param tasks
|
||||
* @param processInstanceId
|
||||
* @return
|
||||
*/
|
||||
private List<WorkflowTask> filterTasksByWorkflowInstance(List<WorkflowTask> tasks, String workflowInstanceId)
|
||||
{
|
||||
List<WorkflowTask> filteredTasks = new ArrayList<WorkflowTask>();
|
||||
for (WorkflowTask task : tasks)
|
||||
{
|
||||
if (task.path.instance.id.equals(workflowInstanceId))
|
||||
{
|
||||
filteredTasks.add(task);
|
||||
}
|
||||
}
|
||||
return filteredTasks;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping default-access="field">
|
||||
|
||||
<subclass name="org.alfresco.repo.workflow.jbpm.WorkflowTaskInstance"
|
||||
extends="org.jbpm.taskmgmt.exe.TaskInstance"
|
||||
discriminator-value="W"/>
|
||||
|
||||
</hibernate-mapping>
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.service.cmr.workflow.WorkflowException;
|
||||
import org.jbpm.graph.def.Transition;
|
||||
import org.jbpm.graph.exe.ExecutionContext;
|
||||
import org.jbpm.taskmgmt.exe.TaskInstance;
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
import org.springframework.beans.factory.access.BeanFactoryReference;
|
||||
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
|
||||
|
||||
|
||||
/**
|
||||
* Alfresco specific implementation of a jBPM task instance
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class WorkflowTaskInstance extends TaskInstance
|
||||
{
|
||||
private static final long serialVersionUID = 6824116036569411964L;
|
||||
|
||||
/** Alfresco JBPM Engine */
|
||||
private static JBPMEngine jbpmEngine = null;
|
||||
|
||||
/**
|
||||
* Gets the JBPM Engine instance
|
||||
*
|
||||
* @return JBPM Engine
|
||||
*/
|
||||
private JBPMEngine getJBPMEngine()
|
||||
{
|
||||
if (jbpmEngine == null)
|
||||
{
|
||||
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
|
||||
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
|
||||
jbpmEngine = (JBPMEngine)factory.getFactory().getBean("jbpm_engine");
|
||||
if (jbpmEngine == null)
|
||||
{
|
||||
throw new WorkflowException("Failed to retrieve JBPMEngine component");
|
||||
}
|
||||
}
|
||||
return jbpmEngine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*/
|
||||
public WorkflowTaskInstance()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param taskName
|
||||
* @param actorId
|
||||
*/
|
||||
public WorkflowTaskInstance(String taskName, String actorId)
|
||||
{
|
||||
super(taskName, actorId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param taskName
|
||||
*/
|
||||
public WorkflowTaskInstance(String taskName)
|
||||
{
|
||||
super(taskName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create(ExecutionContext executionContext)
|
||||
{
|
||||
super.create(executionContext);
|
||||
getJBPMEngine().setDefaultTaskProperties(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(Transition transition)
|
||||
{
|
||||
// NOTE: Set the outcome first, so it's available during the submission of
|
||||
// task variables to the process context
|
||||
Transition outcome = (transition == null) ? token.getNode().getDefaultLeavingTransition() : transition;
|
||||
if (outcome != null)
|
||||
{
|
||||
getJBPMEngine().setTaskOutcome(this, outcome);
|
||||
}
|
||||
super.end(transition);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.jbpm.graph.exe.ExecutionContext;
|
||||
import org.jbpm.taskmgmt.TaskInstanceFactory;
|
||||
import org.jbpm.taskmgmt.exe.TaskInstance;
|
||||
|
||||
|
||||
/**
|
||||
* jBPM factory for creating Alfresco derived Task Instances
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class WorkflowTaskInstanceFactory implements TaskInstanceFactory
|
||||
{
|
||||
private static final long serialVersionUID = -8097108150047415711L;
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jbpm.taskmgmt.TaskInstanceFactory#createTaskInstance(org.jbpm.graph.exe.ExecutionContext)
|
||||
*/
|
||||
public TaskInstance createTaskInstance(ExecutionContext executionContext)
|
||||
{
|
||||
return new WorkflowTaskInstance();
|
||||
}
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
<?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>
|
28
source/java/org/alfresco/repo/workflow/jbpm/jbpm.cfg.xml
Normal file
28
source/java/org/alfresco/repo/workflow/jbpm/jbpm.cfg.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<jbpm-configuration>
|
||||
|
||||
<jbpm-context>
|
||||
<service name="persistence" factory="org.jbpm.persistence.db.DbPersistenceServiceFactory" />
|
||||
<service name="message" factory="org.jbpm.msg.db.DbMessageServiceFactory" />
|
||||
<service name="scheduler" factory="org.jbpm.scheduler.db.DbSchedulerServiceFactory" />
|
||||
<service name="logging" factory="org.jbpm.logging.db.DbLoggingServiceFactory" />
|
||||
<service name="authentication" factory="org.jbpm.security.authentication.DefaultAuthenticationServiceFactory" />
|
||||
</jbpm-context>
|
||||
|
||||
<!-- configuration resource files pointing to default configuration files in jbpm-{version}.jar -->
|
||||
<string name="resource.hibernate.cfg.xml" value="hibernate.cfg.xml" />
|
||||
<string name="resource.business.calendar" value="org/jbpm/calendar/jbpm.business.calendar.properties" />
|
||||
<string name="resource.default.modules" value="org/jbpm/graph/def/jbpm.default.modules.properties" />
|
||||
<string name='resource.converter' value='org/alfresco/repo/workflow/jbpm/jbpm.converter.properties' />
|
||||
<string name="resource.action.types" value="org/jbpm/graph/action/action.types.xml" />
|
||||
<string name="resource.node.types" value="org/jbpm/graph/node/node.types.xml" />
|
||||
<string name="resource.parsers" value="org/jbpm/jpdl/par/jbpm.parsers.xml" />
|
||||
<string name="resource.varmapping" value="org/alfresco/repo/workflow/jbpm/jbpm.varmapping.xml" />
|
||||
|
||||
<long name="jbpm.msg.wait.timout" value="5000" singleton="true" />
|
||||
<int name="jbpm.byte.block.size" value="1024" singleton="true" />
|
||||
<string name="mail.smtp.host" value="localhost" />
|
||||
<bean name="jbpm.task.instance.factory" class="org.alfresco.repo.workflow.jbpm.WorkflowTaskInstanceFactory" singleton="true" />
|
||||
<bean name="jbpm.variable.resolver" class="org.jbpm.jpdl.el.impl.JbpmVariableResolver" singleton="true" />
|
||||
<bean name="jbpm.mail.address.resolver" class="org.jbpm.identity.mail.IdentityAddressResolver" singleton="true" />
|
||||
|
||||
</jbpm-configuration>
|
@@ -0,0 +1,19 @@
|
||||
# this file contains the mappings between converter types
|
||||
# and the char that is used in the database. this mapping
|
||||
# is used by the ConverterEnumType to store the VariableInstance
|
||||
# converter field. The Converters class provides singleton access
|
||||
# to these converter classes.
|
||||
|
||||
B org.jbpm.context.exe.converter.BooleanToStringConverter
|
||||
Y org.jbpm.context.exe.converter.BytesToByteArrayConverter
|
||||
E org.jbpm.context.exe.converter.ByteToLongConverter
|
||||
C org.jbpm.context.exe.converter.CharacterToStringConverter
|
||||
A org.jbpm.context.exe.converter.DateToLongConverter
|
||||
D org.jbpm.context.exe.converter.DoubleToStringConverter
|
||||
F org.jbpm.context.exe.converter.FloatToStringConverter
|
||||
G org.jbpm.context.exe.converter.FloatToDoubleConverter
|
||||
I org.jbpm.context.exe.converter.IntegerToLongConverter
|
||||
R org.jbpm.context.exe.converter.SerializableToByteArrayConverter
|
||||
H org.jbpm.context.exe.converter.ShortToLongConverter
|
||||
N org.alfresco.repo.workflow.jbpm.NodeConverter
|
||||
L org.alfresco.repo.workflow.jbpm.NodeListConverter
|
190
source/java/org/alfresco/repo/workflow/jbpm/jbpm.varmapping.xml
Normal file
190
source/java/org/alfresco/repo/workflow/jbpm/jbpm.varmapping.xml
Normal file
@@ -0,0 +1,190 @@
|
||||
<!--
|
||||
# This file specifies how jbpm will store variables into the database.
|
||||
#
|
||||
# If jbpm needs to determine how to store a variable into the database,
|
||||
# the jbpm-types below or scanned in sequence as they are specified here.
|
||||
# For each jbpm-type, jbpm will see if the give variable object matches
|
||||
# with the matcher bean. If there is a match, the converter (optional)
|
||||
# and the variable instance will be used to store and retrieve
|
||||
# the variable value for the rest of its lifetime till the variable is
|
||||
# deleted.
|
||||
-->
|
||||
<jbpm-types>
|
||||
|
||||
<list name="jbpm.types" singleton="true">
|
||||
|
||||
<!-- java.lang.String -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="java.lang.String" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.StringInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- java.lang.Boolean -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="java.lang.Boolean" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<converter class="org.jbpm.context.exe.converter.BooleanToStringConverter" />
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.StringInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- java.lang.Character -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="java.lang.Character" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<converter class="org.jbpm.context.exe.converter.CharacterToStringConverter" />
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.StringInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- java.lang.Long -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="java.lang.Long" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.LongInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- java.lang.Byte -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="java.lang.Byte" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<converter class="org.jbpm.context.exe.converter.ByteToLongConverter" />
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.LongInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- java.lang.Short -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="java.lang.Short" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<converter class="org.jbpm.context.exe.converter.ShortToLongConverter" />
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.LongInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- java.lang.Integer -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="java.lang.Integer" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<converter class="org.jbpm.context.exe.converter.IntegerToLongConverter" />
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.LongInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- java.lang.Double -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="java.lang.Double" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.DoubleInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- java.lang.Float -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="java.lang.Float" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<converter class="org.jbpm.context.exe.converter.FloatToDoubleConverter" />
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.DoubleInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- java.util.Date -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="java.util.Date" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.DateInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- org.alfresco.repo.workflow.jbpm.JBPMNode -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="org.alfresco.repo.workflow.jbpm.JBPMNode" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<converter class="org.alfresco.repo.workflow.jbpm.NodeConverter" />
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.StringInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- org.alfresco.repo.workflow.jbpm.JBPMNodeList -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="org.alfresco.repo.workflow.jbpm.JBPMNodeList" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<converter class="org.alfresco.repo.workflow.jbpm.NodeListConverter" />
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.ByteArrayInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- byte[] -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
|
||||
<field name="className"><string value="[B" /></field>
|
||||
</bean>
|
||||
</matcher>
|
||||
<converter class="org.jbpm.context.exe.converter.BytesToByteArrayConverter" />
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.ByteArrayInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- java.io.Serializable -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.SerializableMatcher" />
|
||||
</matcher>
|
||||
<converter class="org.jbpm.context.exe.converter.SerializableToByteArrayConverter" />
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.ByteArrayInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- hibernatable long id types -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.HibernateLongIdMatcher" />
|
||||
</matcher>
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.HibernateLongInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- hibernatable string id types -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.HibernateStringIdMatcher" />
|
||||
</matcher>
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.HibernateStringInstance" />
|
||||
</jbpm-type>
|
||||
|
||||
<!-- hibernatable ejb3 types -->
|
||||
<jbpm-type>
|
||||
<matcher>
|
||||
<bean class="org.jbpm.context.exe.matcher.Ejb3Matcher" />
|
||||
</matcher>
|
||||
<variable-instance class="org.jbpm.context.exe.variableinstance.Ejb3Instance" />
|
||||
</jbpm-type>
|
||||
|
||||
</list>
|
||||
|
||||
</jbpm-types>
|
@@ -0,0 +1,63 @@
|
||||
<?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>
|
@@ -0,0 +1,14 @@
|
||||
test.workflow.title=Test
|
||||
test.workflow.description=Workflow for testing purposes
|
||||
|
||||
test.node.start.title=Start
|
||||
test.node.start.description=The Start
|
||||
test.node.review.title=Review
|
||||
test.node.review.description=The Review
|
||||
test.node.end.title=End
|
||||
test.node.end.description=The End
|
||||
|
||||
test.node.start.transition.review=Review
|
||||
|
||||
test.task.submit.title=Submit Review Title
|
||||
test.task.submit.description=Submit Review Description
|
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<process-definition xmlns="urn:jbpm.org:jpdl-3.1" name="test">
|
||||
<swimlane name="initiator"></swimlane>
|
||||
|
||||
<start-state name="start">
|
||||
<task name="submit" swimlane="initiator">
|
||||
<controller>
|
||||
<variable name="reviewer" access="write,required" />
|
||||
<variable name="testNode" access="write,required" />
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="" to="review">
|
||||
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
|
||||
<script>
|
||||
<expression>
|
||||
function result()
|
||||
{
|
||||
return ("Initiator: " + initiator.properties["cm:userName"] + ", process instance = " + executionContext.processInstance.id + ", testNode children = " + testNode.children.length);
|
||||
}
|
||||
result();
|
||||
</expression>
|
||||
<variable name="scriptResult" access="write"/>
|
||||
</script>
|
||||
</action>
|
||||
</transition>
|
||||
<transition name="end" to="end"/>
|
||||
</start-state>
|
||||
|
||||
<swimlane name="reviewer">
|
||||
<assignment actor-id="#{reviewer}"></assignment>
|
||||
</swimlane>
|
||||
|
||||
<task-node name="review">
|
||||
<event type="node-enter">
|
||||
<script>
|
||||
System.out.println("the reviewer is " + reviewer);
|
||||
System.out.println("node " + testNode.name + " contains " + testNode.children.length + " children");
|
||||
System.out.println("scriptResult = " + scriptResult);
|
||||
</script>
|
||||
</event>
|
||||
<task name="review" duedate="1 business day" blocking="true" swimlane="reviewer">
|
||||
<controller>
|
||||
<variable name="comment" access="read,write,required"></variable>
|
||||
</controller>
|
||||
</task>
|
||||
<transition name="" to="end"></transition>
|
||||
</task-node>
|
||||
|
||||
<end-state name="end"></end-state>
|
||||
|
||||
</process-definition>
|
57
source/java/org/alfresco/repo/workflow/jbpm/test_script.xml
Normal file
57
source/java/org/alfresco/repo/workflow/jbpm/test_script.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<process-definition xmlns="urn:jbpm.org:jpdl-3.1" name="test_script">
|
||||
<swimlane name="initiator"></swimlane>
|
||||
|
||||
<start-state name="start">
|
||||
<task name="submit" swimlane="initiator">
|
||||
<event type="task-assign">
|
||||
<script>
|
||||
System.out.println("taskInstance.create: " + taskInstance.create);
|
||||
</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>
|
||||
|
||||
</process-definition>
|
Reference in New Issue
Block a user