mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Workflow checkpoint:
- BPM Engine Registry & Plug-in SPIs - First JBoss JBPM based Implementation of SPIs - Workflow Service Implementation - Tests git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3436 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
757
source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java
Normal file
757
source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java
Normal file
@@ -0,0 +1,757 @@
|
||||
/*
|
||||
* 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.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.workflow.BPMEngine;
|
||||
import org.alfresco.repo.workflow.TaskComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowDefinitionComponent;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowInstance;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowNode;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowPath;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.jbpm.JbpmContext;
|
||||
import org.jbpm.JbpmException;
|
||||
import org.jbpm.context.exe.ContextInstance;
|
||||
import org.jbpm.db.GraphSession;
|
||||
import org.jbpm.db.TaskMgmtSession;
|
||||
import org.jbpm.graph.def.Node;
|
||||
import org.jbpm.graph.def.ProcessDefinition;
|
||||
import org.jbpm.graph.def.Transition;
|
||||
import org.jbpm.graph.exe.ProcessInstance;
|
||||
import org.jbpm.graph.exe.Token;
|
||||
import org.jbpm.taskmgmt.def.Task;
|
||||
import org.jbpm.taskmgmt.exe.TaskInstance;
|
||||
import org.springmodules.workflow.jbpm31.JbpmCallback;
|
||||
import org.springmodules.workflow.jbpm31.JbpmTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* JBoss JBPM based implementation of:
|
||||
*
|
||||
* Workflow Definition Component
|
||||
* Workflow Component
|
||||
* Task Component
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class JBPMEngine extends BPMEngine
|
||||
implements WorkflowDefinitionComponent, WorkflowComponent, TaskComponent
|
||||
{
|
||||
// Implementation dependencies
|
||||
protected DictionaryService dictionaryService;
|
||||
protected NamespaceService namespaceService;
|
||||
private JbpmTemplate jbpmTemplate;
|
||||
|
||||
/**
|
||||
* Sets the JBPM Template used for accessing JBoss JBPM in the correct context
|
||||
*
|
||||
* @param jbpmTemplate
|
||||
*/
|
||||
public void setJBPMTemplate(JbpmTemplate jbpmTemplate)
|
||||
{
|
||||
this.jbpmTemplate = jbpmTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Dictionary Service
|
||||
*
|
||||
* @param dictionaryService
|
||||
*/
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Namespace Service
|
||||
*
|
||||
* @param namespaceService
|
||||
*/
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Workflow Definition...
|
||||
//
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowDefinitionComponent#deployDefinition(java.io.InputStream)
|
||||
*/
|
||||
public WorkflowDefinition deployDefinition(InputStream workflowDefinition)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowDefinitionComponent#undeployDefinition(java.lang.String)
|
||||
*/
|
||||
public void undeployDefinition(String workflowDefinitionId)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowDefinitionComponent#getDefinitions()
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<WorkflowDefinition> getDefinitions()
|
||||
{
|
||||
try
|
||||
{
|
||||
return (List<WorkflowDefinition>)jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public Object doInJbpm(JbpmContext context)
|
||||
{
|
||||
GraphSession graphSession = context.getGraphSession();
|
||||
List<ProcessDefinition> processDefs = (List<ProcessDefinition>)graphSession.findLatestProcessDefinitions();
|
||||
List<WorkflowDefinition> workflowDefs = new ArrayList<WorkflowDefinition>(processDefs.size());
|
||||
for (ProcessDefinition processDef : processDefs)
|
||||
{
|
||||
WorkflowDefinition workflowDef = createWorkflowDefinition(processDef);
|
||||
workflowDefs.add(workflowDef);
|
||||
}
|
||||
return workflowDefs;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to retrieve workflow definitions", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowDefinitionComponent#getDefinitionById(java.lang.String)
|
||||
*/
|
||||
public WorkflowDefinition getDefinitionById(String workflowDefinitionId)
|
||||
{
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Workflow Instance Management...
|
||||
//
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowComponent#startWorkflow(java.lang.String, java.util.Map)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public WorkflowPath startWorkflow(final String workflowDefinitionId, final Map<QName, Serializable> parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (WorkflowPath) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public Object doInJbpm(JbpmContext context)
|
||||
{
|
||||
// initialise jBPM actor (for any processes that wish to record the initiator)
|
||||
context.setActorId(AuthenticationUtil.getCurrentUserName());
|
||||
|
||||
// construct a new process
|
||||
GraphSession graphSession = context.getGraphSession();
|
||||
ProcessDefinition processDefinition = graphSession.loadProcessDefinition(getJbpmId(workflowDefinitionId));
|
||||
ProcessInstance processInstance = new ProcessInstance(processDefinition);
|
||||
Token token = processInstance.getRootToken();
|
||||
|
||||
// create the start task if one exists
|
||||
Task startTask = processInstance.getTaskMgmtInstance().getTaskMgmtDefinition().getStartTask();
|
||||
if (startTask != null)
|
||||
{
|
||||
TaskInstance taskInstance = processInstance.getTaskMgmtInstance().createStartTaskInstance();
|
||||
setTaskProperties(taskInstance, parameters);
|
||||
token = taskInstance.getToken();
|
||||
}
|
||||
|
||||
// Save the process instance along with the task instance
|
||||
context.save(processInstance);
|
||||
return createWorkflowPath(token);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to start workflow " + workflowDefinitionId, e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowComponent#getActiveWorkflows(java.lang.String)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<WorkflowInstance> getActiveWorkflows(final String workflowDefinitionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (List<WorkflowInstance>) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public Object doInJbpm(JbpmContext context)
|
||||
{
|
||||
GraphSession graphSession = context.getGraphSession();
|
||||
List<ProcessInstance> processInstances = graphSession.findProcessInstances(getJbpmId(workflowDefinitionId));
|
||||
List<WorkflowInstance> workflowInstances = new ArrayList<WorkflowInstance>(processInstances.size());
|
||||
for (ProcessInstance processInstance : processInstances)
|
||||
{
|
||||
if (!processInstance.hasEnded())
|
||||
{
|
||||
WorkflowInstance workflowInstance = createWorkflowInstance(processInstance);
|
||||
workflowInstances.add(workflowInstance);
|
||||
}
|
||||
}
|
||||
return workflowInstances;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to retrieve workflow instances for definition '" + workflowDefinitionId + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowComponent#getWorkflowPaths(java.lang.String)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<WorkflowPath> getWorkflowPaths(final String workflowId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (List<WorkflowPath>) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public Object doInJbpm(JbpmContext context)
|
||||
{
|
||||
// retrieve process instance
|
||||
GraphSession graphSession = context.getGraphSession();
|
||||
ProcessInstance processInstance = graphSession.loadProcessInstance(getJbpmId(workflowId));
|
||||
|
||||
// convert jBPM tokens to workflow posisitons
|
||||
List<Token> tokens = processInstance.findAllTokens();
|
||||
List<WorkflowPath> paths = new ArrayList<WorkflowPath>(tokens.size());
|
||||
for (Token token : tokens)
|
||||
{
|
||||
if (!token.hasEnded())
|
||||
{
|
||||
WorkflowPath path = createWorkflowPath(token);
|
||||
paths.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to retrieve workflow paths for workflow instance '" + workflowId + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowComponent#cancelWorkflow(java.lang.String)
|
||||
*/
|
||||
public WorkflowInstance cancelWorkflow(final String workflowId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (WorkflowInstance) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public Object doInJbpm(JbpmContext context)
|
||||
{
|
||||
// retrieve and cancel process instance
|
||||
GraphSession graphSession = context.getGraphSession();
|
||||
ProcessInstance processInstance = graphSession.loadProcessInstance(getJbpmId(workflowId));
|
||||
processInstance.end();
|
||||
|
||||
// save the process instance along with the task instance
|
||||
context.save(processInstance);
|
||||
return createWorkflowInstance(processInstance);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to cancel workflow instance '" + workflowId + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowComponent#signal(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public WorkflowPath signal(final String pathId, final String transition)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (WorkflowPath) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public Object doInJbpm(JbpmContext context)
|
||||
{
|
||||
// retrieve jBPM token for workflow position
|
||||
GraphSession graphSession = context.getGraphSession();
|
||||
Token token = getWorkflowToken(graphSession, pathId);
|
||||
|
||||
// signal the transition
|
||||
if (transition == null)
|
||||
{
|
||||
token.signal();
|
||||
}
|
||||
else
|
||||
{
|
||||
Node node = token.getNode();
|
||||
if (!node.hasLeavingTransition(transition))
|
||||
{
|
||||
throw new WorkflowException("Transition '" + transition + "' is invalid for Workflow path '" + pathId + "'");
|
||||
}
|
||||
token.signal(transition);
|
||||
}
|
||||
|
||||
// save
|
||||
ProcessInstance processInstance = token.getProcessInstance();
|
||||
context.save(processInstance);
|
||||
|
||||
// return new workflow path
|
||||
return createWorkflowPath(token);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to signal transition '" + transition + "' from workflow path '" + pathId + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.WorkflowComponent#getTasksForWorkflowPath(java.lang.String)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<WorkflowTask> getTasksForWorkflowPath(final String pathId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (List<WorkflowTask>) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public List<WorkflowTask> doInJbpm(JbpmContext context)
|
||||
{
|
||||
// retrieve tasks at specified workflow path
|
||||
GraphSession graphSession = context.getGraphSession();
|
||||
Token token = getWorkflowToken(graphSession, pathId);
|
||||
TaskMgmtSession taskSession = context.getTaskMgmtSession();
|
||||
List<TaskInstance> tasks = taskSession.findTaskInstancesByToken(token.getId());
|
||||
List<WorkflowTask> workflowTasks = new ArrayList<WorkflowTask>(tasks.size());
|
||||
for (TaskInstance task : tasks)
|
||||
{
|
||||
WorkflowTask workflowTask = createWorkflowTask(task);
|
||||
workflowTasks.add(workflowTask);
|
||||
}
|
||||
return workflowTasks;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to retrieve tasks assigned at Workflow path '" + pathId + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Task Management ...
|
||||
//
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.TaskComponent#getAssignedTasks(java.lang.String, org.alfresco.service.cmr.workflow.WorkflowTaskState)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<WorkflowTask> getAssignedTasks(final String authority, final WorkflowTaskState state)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (List<WorkflowTask>) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public List<WorkflowTask> doInJbpm(JbpmContext context)
|
||||
{
|
||||
// retrieve tasks assigned to authority
|
||||
TaskMgmtSession taskSession = context.getTaskMgmtSession();
|
||||
List<TaskInstance> tasks = taskSession.findTaskInstances(authority);
|
||||
List<WorkflowTask> workflowTasks = new ArrayList<WorkflowTask>(tasks.size());
|
||||
for (TaskInstance task : tasks)
|
||||
{
|
||||
if (getWorkflowTaskState(task).equals(state))
|
||||
{
|
||||
WorkflowTask workflowTask = createWorkflowTask(task);
|
||||
workflowTasks.add(workflowTask);
|
||||
}
|
||||
}
|
||||
return workflowTasks;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to retrieve tasks assigned to authority '" + authority + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.TaskComponent#getPooledTasks(java.util.List)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<WorkflowTask> getPooledTasks(final List<String> authorities)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (List<WorkflowTask>) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public List<WorkflowTask> doInJbpm(JbpmContext context)
|
||||
{
|
||||
// retrieve pooled tasks for specified authorities
|
||||
TaskMgmtSession taskSession = context.getTaskMgmtSession();
|
||||
List<TaskInstance> tasks = taskSession.findPooledTaskInstances(authorities);
|
||||
List<WorkflowTask> workflowTasks = new ArrayList<WorkflowTask>(tasks.size());
|
||||
for (TaskInstance task : tasks)
|
||||
{
|
||||
WorkflowTask workflowTask = createWorkflowTask(task);
|
||||
workflowTasks.add(workflowTask);
|
||||
}
|
||||
return workflowTasks;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to retrieve pooled tasks for authorities '" + authorities + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.TaskComponent#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)
|
||||
{
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.TaskComponent#endTask(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public WorkflowTask endTask(final String taskId, final String transition)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (WorkflowTask) jbpmTemplate.execute(new JbpmCallback()
|
||||
{
|
||||
public Object doInJbpm(JbpmContext context)
|
||||
{
|
||||
// retrieve task
|
||||
TaskMgmtSession taskSession = context.getTaskMgmtSession();
|
||||
TaskInstance taskInstance = taskSession.loadTaskInstance(getJbpmId(taskId));
|
||||
|
||||
// signal the transition on the task
|
||||
if (transition == null)
|
||||
{
|
||||
taskInstance.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
Node node = taskInstance.getTask().getTaskNode();
|
||||
if (node.getLeavingTransition(transition) == null)
|
||||
{
|
||||
throw new WorkflowException("Transition '" + transition + "' is invalid for Workflow task '" + taskId + "'");
|
||||
}
|
||||
taskInstance.end(transition);
|
||||
}
|
||||
|
||||
// save
|
||||
ProcessInstance processInstance = taskInstance.getToken().getProcessInstance();
|
||||
context.save(processInstance);
|
||||
|
||||
// note: the ending of a task may not have signalled (i.e. more than one task exists at
|
||||
// this node)
|
||||
return createWorkflowTask(taskInstance);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(JbpmException e)
|
||||
{
|
||||
throw new WorkflowException("Failed to signal transition '" + transition + "' from workflow task '" + taskId + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.TaskComponent#getTaskById(java.lang.String)
|
||||
*/
|
||||
public WorkflowTask getTaskById(String taskId)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Properties of Task
|
||||
*
|
||||
* @param instance task instance
|
||||
* @param properties properties to set
|
||||
*/
|
||||
protected void setTaskProperties(TaskInstance instance, Map<QName, Serializable> properties)
|
||||
{
|
||||
if (properties == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Use Dictionary to drive mapping
|
||||
|
||||
// TODO: Determine if NodeRefs and collection of NodeRefs need to be converted to String
|
||||
|
||||
ContextInstance context = instance.getContextInstance();
|
||||
for (Entry<QName, Serializable> entry : properties.entrySet())
|
||||
{
|
||||
String name = null;
|
||||
QName qname = entry.getKey();
|
||||
if (qname.getNamespaceURI().equals(NamespaceService.DEFAULT_URI))
|
||||
{
|
||||
name = qname.getLocalName();
|
||||
}
|
||||
else
|
||||
{
|
||||
name = qname.toPrefixString(namespaceService);
|
||||
}
|
||||
context.setVariable(name, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Helpers...
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* Get JBoss JBPM Id from Engine Global Id
|
||||
*
|
||||
* @param id global id
|
||||
* @return JBoss JBPM Id
|
||||
*/
|
||||
protected long getJbpmId(String id)
|
||||
{
|
||||
try
|
||||
{
|
||||
String theLong = createLocalId(id);
|
||||
return new Long(theLong);
|
||||
}
|
||||
catch(NumberFormatException e)
|
||||
{
|
||||
throw new WorkflowException("Format of id '" + id + "' is invalid", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JBoss JBPM Token for the Workflow Path
|
||||
*
|
||||
* @param session JBoss JBPM Graph Session
|
||||
* @param pathId workflow path id
|
||||
* @return JBoss JBPM Token
|
||||
*/
|
||||
protected Token getWorkflowToken(GraphSession session, String pathId)
|
||||
{
|
||||
// extract process id and token path within process
|
||||
String[] path = pathId.split("::");
|
||||
if (path.length != 2)
|
||||
{
|
||||
throw new WorkflowException("Invalid workflow path '" + pathId + "'");
|
||||
}
|
||||
|
||||
// retrieve jBPM token for workflow position
|
||||
ProcessInstance processInstance = session.loadProcessInstance(getJbpmId(path[0]));
|
||||
Token token = processInstance.findToken(path[1]);
|
||||
if (token == null)
|
||||
{
|
||||
throw new WorkflowException("Workflow path '" + pathId + "' does not exist");
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Workflow Data Object Creation...
|
||||
//
|
||||
|
||||
/**
|
||||
* Creates a Workflow Path
|
||||
*
|
||||
* @param token JBoss JBPM Token
|
||||
* @return Workflow Path
|
||||
*/
|
||||
protected WorkflowPath createWorkflowPath(Token token)
|
||||
{
|
||||
WorkflowPath path = new WorkflowPath();
|
||||
path.id = createGlobalId(token.getProcessInstance().getId() + "::" + token.getFullName());
|
||||
path.instance = createWorkflowInstance(token.getProcessInstance());
|
||||
path.node = createWorkflowNode(token.getNode());
|
||||
path.active = !token.hasEnded();
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Workflow Node
|
||||
*
|
||||
* @param node JBoss JBPM Node
|
||||
* @return Workflow Node
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected WorkflowNode createWorkflowNode(Node node)
|
||||
{
|
||||
WorkflowNode workflowNode = new WorkflowNode();
|
||||
workflowNode.name = node.getName();
|
||||
if (node instanceof HibernateProxy)
|
||||
{
|
||||
Node realNode = (Node)((HibernateProxy)node).getHibernateLazyInitializer().getImplementation();
|
||||
workflowNode.type = realNode.getClass().getSimpleName();
|
||||
}
|
||||
else
|
||||
{
|
||||
workflowNode.type = node.getClass().getSimpleName();
|
||||
}
|
||||
// TODO: Is there a formal way of determing if task node?
|
||||
workflowNode.isTaskNode = workflowNode.type.equals("TaskNode");
|
||||
List transitions = node.getLeavingTransitions();
|
||||
workflowNode.transitions = new String[transitions.size()];
|
||||
int i = 0;
|
||||
for (Transition transition : (List<Transition>)transitions)
|
||||
{
|
||||
workflowNode.transitions[i++] = transition.getName();
|
||||
}
|
||||
return workflowNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Workflow Instance
|
||||
*
|
||||
* @param instance JBoss JBPM Process Instance
|
||||
* @return Workflow instance
|
||||
*/
|
||||
protected WorkflowInstance createWorkflowInstance(ProcessInstance instance)
|
||||
{
|
||||
WorkflowInstance workflowInstance = new WorkflowInstance();
|
||||
workflowInstance.id = createGlobalId(new Long(instance.getId()).toString());
|
||||
workflowInstance.definition = createWorkflowDefinition(instance.getProcessDefinition());
|
||||
workflowInstance.active = !instance.hasEnded();
|
||||
return workflowInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Workflow Definition
|
||||
*
|
||||
* @param definition JBoss Process Definition
|
||||
* @return Workflow Definition
|
||||
*/
|
||||
protected WorkflowDefinition createWorkflowDefinition(ProcessDefinition definition)
|
||||
{
|
||||
WorkflowDefinition workflowDef = new WorkflowDefinition();
|
||||
workflowDef.id = createGlobalId(new Long(definition.getId()).toString());
|
||||
workflowDef.name = definition.getName();
|
||||
Task startTask = definition.getTaskMgmtDefinition().getStartTask();
|
||||
if (startTask != null)
|
||||
{
|
||||
workflowDef.startTaskDefinition = createWorkflowTaskDefinition(startTask);
|
||||
}
|
||||
|
||||
return workflowDef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Workflow Task
|
||||
*
|
||||
* @param task JBoss Task Instance
|
||||
* @return Workflow Task
|
||||
*/
|
||||
protected WorkflowTask createWorkflowTask(TaskInstance task)
|
||||
{
|
||||
WorkflowTask workflowTask = new WorkflowTask();
|
||||
workflowTask.id = createGlobalId(new Long(task.getId()).toString());
|
||||
workflowTask.name = task.getName();
|
||||
workflowTask.path = createWorkflowPath(task.getToken());
|
||||
workflowTask.state = getWorkflowTaskState(task);
|
||||
workflowTask.definition = createWorkflowTaskDefinition(task.getTask());
|
||||
|
||||
// TODO: Properties and Associations
|
||||
|
||||
return workflowTask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Workflow Task Definition
|
||||
*
|
||||
* @param task JBoss JBPM Task
|
||||
* @return Workflow Task Definition
|
||||
*/
|
||||
protected WorkflowTaskDefinition createWorkflowTaskDefinition(Task task)
|
||||
{
|
||||
// TODO: Extend jBPM task instance to include dictionary definition qname
|
||||
WorkflowTaskDefinition taskDef = new WorkflowTaskDefinition();
|
||||
taskDef.id = task.getName();
|
||||
QName typeName = QName.createQName(taskDef.id, namespaceService);
|
||||
taskDef.metadata = dictionaryService.getType(typeName);
|
||||
return taskDef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Workflow Task State for the specified JBoss JBPM Task
|
||||
*
|
||||
* @param task task
|
||||
* @return task state
|
||||
*/
|
||||
protected WorkflowTaskState getWorkflowTaskState(TaskInstance task)
|
||||
{
|
||||
if (task.hasEnded())
|
||||
{
|
||||
return WorkflowTaskState.COMPLETED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return WorkflowTaskState.IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
215
source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java
Normal file
215
source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.workflow.BPMEngineRegistry;
|
||||
import org.alfresco.repo.workflow.TaskComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowComponent;
|
||||
import org.alfresco.repo.workflow.WorkflowDefinitionComponent;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowInstance;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowPath;
|
||||
import org.alfresco.service.cmr.workflow.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;
|
||||
|
||||
|
||||
/**
|
||||
* JBPM Engine Tests
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class JBPMEngineTest extends BaseSpringTest
|
||||
{
|
||||
WorkflowDefinitionComponent workflowDefinitionComponent;
|
||||
WorkflowComponent workflowComponent;
|
||||
TaskComponent taskComponent;
|
||||
|
||||
|
||||
//@Override
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
BPMEngineRegistry registry = (BPMEngineRegistry)applicationContext.getBean("bpm_engineRegistry");
|
||||
workflowDefinitionComponent = registry.getWorkflowDefinitionComponent("jbpm");
|
||||
workflowComponent = registry.getWorkflowComponent("jbpm");
|
||||
taskComponent = registry.getTaskComponent("jbpm");
|
||||
}
|
||||
|
||||
|
||||
public void testGetWorkflowDefinitions()
|
||||
{
|
||||
List<WorkflowDefinition> workflowDefs = workflowDefinitionComponent.getDefinitions();
|
||||
assertNotNull(workflowDefs);
|
||||
assertTrue(workflowDefs.size() > 0);
|
||||
}
|
||||
|
||||
|
||||
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 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();
|
||||
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), "admin");
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
||||
assertNotNull(path);
|
||||
WorkflowPath updatedPath = workflowComponent.signal(path.id, path.node.transitions[0]);
|
||||
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");
|
||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
||||
assertNotNull(path);
|
||||
assertNotNull(path);
|
||||
WorkflowPath updatedPath = workflowComponent.signal(path.id, path.node.transitions[0]);
|
||||
assertNotNull(updatedPath);
|
||||
List<WorkflowTask> completedTasks = taskComponent.getAssignedTasks("admin", WorkflowTaskState.COMPLETED);
|
||||
assertNotNull(completedTasks);
|
||||
assertEquals(0, completedTasks.size());
|
||||
List<WorkflowTask> assignedTasks = taskComponent.getAssignedTasks("admin", WorkflowTaskState.IN_PROGRESS);
|
||||
assertNotNull(assignedTasks);
|
||||
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");
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Locate the Test Workflow Definition
|
||||
*
|
||||
* @return workflow definition
|
||||
*/
|
||||
private WorkflowDefinition getTestDefinition()
|
||||
{
|
||||
List<WorkflowDefinition> workflowDefs = workflowDefinitionComponent.getDefinitions();
|
||||
for (WorkflowDefinition workflowDef : workflowDefs)
|
||||
{
|
||||
if (workflowDef.name.equals("Review and Approve"))
|
||||
{
|
||||
return workflowDef;
|
||||
}
|
||||
}
|
||||
fail("Test Workflow Definition not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user