- Workflow Service

-- addition of get process definition history
-- addition of get active timers (for a process definition)
-- addition of fire custom workflow events
-- addition of get process variables

- Workflow Console
-- addition of undeploy all versions of a process definition
-- addition of list all versions of a process definition
-- addition of list workflows for previous version of a process definition
-- addition of query tasks
-- addition of firing custom workflow event
-- addition of list timers
-- addition of show process variables

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5754 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
David Caruana
2007-05-22 17:48:11 +00:00
parent 28996e9a03
commit 3682ff9474
8 changed files with 882 additions and 64 deletions

View File

@@ -35,6 +35,7 @@ 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.cmr.workflow.WorkflowTimer;
import org.alfresco.service.namespace.QName;
@@ -88,6 +89,14 @@ public interface WorkflowComponent
*/
public List<WorkflowDefinition> getDefinitions();
/**
* Gets all deployed Workflow Definitions (with all previous versions)
*
* @return the deployed (and previous) workflow definitions
*/
@Auditable
public List<WorkflowDefinition> getAllDefinitions();
/**
* Gets a Workflow Definition by unique Id
*
@@ -104,6 +113,15 @@ public interface WorkflowComponent
*/
public WorkflowDefinition getDefinitionByName(String workflowName);
/**
* Gets all (including previous) Workflow Definitions for the given unique name
*
* @param workflowName workflow name e.g. jbpm://review
* @return the deployed workflow definition (or null if not found)
*/
@Auditable(parameters = {"workflowName"})
public List<WorkflowDefinition> getAllDefinitionsByName(String workflowName);
/**
* Gets a graphical view of the Workflow Definition
*
@@ -152,6 +170,14 @@ public interface WorkflowComponent
*/
public List<WorkflowPath> getWorkflowPaths(String workflowId);
/**
* Gets the properties associated with the specified path (and parent paths)
*
* @param pathId workflow path id
* @return map of path properties
*/
public Map<QName, Serializable> getPathProperties(String pathId);
/**
* Cancel an "in-fligth" Workflow instance
*
@@ -178,6 +204,15 @@ public interface WorkflowComponent
*/
public WorkflowPath signal(String pathId, String transitionId);
/**
* Fire custom event against specified path
*
* @param pathId the workflow path to fire event on
* @param event name of event
* @return workflow path (it may have been updated as a result of firing the event
*/
public WorkflowPath fireEvent(String pathId, String event);
/**
* Gets all Tasks associated with the specified path
*
@@ -185,6 +220,13 @@ public interface WorkflowComponent
* @return the list of associated tasks
*/
public List<WorkflowTask> getTasksForWorkflowPath(String pathId);
/**
* Gets all active timers for the specified workflow
*
* @return the list of active timers
*/
public List<WorkflowTimer> getTimers(String workflowId);
}

View File

@@ -37,17 +37,17 @@ import java.util.List;
import java.util.Map;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.authority.AuthorityDAO;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avmsync.AVMDifference;
import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.authority.AuthorityDAO;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ContentWriter;
@@ -61,7 +61,9 @@ 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.WorkflowTaskQuery;
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
import org.alfresco.service.cmr.workflow.WorkflowTimer;
import org.alfresco.service.cmr.workflow.WorkflowTransition;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
@@ -351,7 +353,22 @@ public class WorkflowInterpreter
else if (command[1].equals("definitions"))
{
List<WorkflowDefinition> defs = workflowService.getDefinitions();
List<WorkflowDefinition> defs = null;
if (command.length == 3)
{
if (command[2].equals("all"))
{
defs = workflowService.getAllDefinitions();
}
else
{
return "Syntax Error.\n";
}
}
else
{
defs = workflowService.getDefinitions();
}
for (WorkflowDefinition def : defs)
{
out.println("id: " + def.id + " , name: " + def.name + " , title: " + def.title + " , version: " + def.version);
@@ -379,12 +396,12 @@ public class WorkflowInterpreter
if (id.equals("all"))
{
for (WorkflowDefinition def : workflowService.getDefinitions())
for (WorkflowDefinition def : workflowService.getAllDefinitions())
{
List<WorkflowInstance> workflows = workflowService.getActiveWorkflows(def.id);
for (WorkflowInstance workflow : workflows)
{
out.println("id: " + workflow.id + " , desc: " + workflow.description + " , start date: " + workflow.startDate + " , def: " + workflow.definition.title);
out.println("id: " + workflow.id + " , desc: " + workflow.description + " , start date: " + workflow.startDate + " , def: " + workflow.definition.name + " v" + workflow.definition.version);
}
}
}
@@ -393,7 +410,7 @@ public class WorkflowInterpreter
List<WorkflowInstance> workflows = workflowService.getActiveWorkflows(id);
for (WorkflowInstance workflow : workflows)
{
out.println("id: " + workflow.id + " , desc: " + workflow.description + " , start date: " + workflow.startDate + " , def: " + workflow.definition.title);
out.println("id: " + workflow.id + " , desc: " + workflow.description + " , start date: " + workflow.startDate + " , def: " + workflow.definition.name);
}
}
}
@@ -453,6 +470,54 @@ public class WorkflowInterpreter
}
}
else if (command[1].equals("timers"))
{
String id = (currentWorkflowDef != null) ? currentWorkflowDef.id : null;
if (id == null && command.length == 2)
{
return "workflow definition not in use. Enter command 'show timers all' or 'use <workflowDefId>'.\n";
}
if (command.length == 3)
{
if (command[2].equals("all"))
{
id = "all";
}
else
{
return "Syntax Error.\n";
}
}
if (id.equals("all"))
{
for (WorkflowDefinition def : workflowService.getAllDefinitions())
{
List<WorkflowInstance> workflows = workflowService.getActiveWorkflows(def.id);
for (WorkflowInstance workflow : workflows)
{
List<WorkflowTimer> timers = workflowService.getTimers(workflow.id);
for (WorkflowTimer timer : timers)
{
out.println("id: " + timer.id + " , name: " + timer.name + " , due date: " + timer.dueDate + " , path: " + timer.path.id + " , node: " + timer.path.node.name + " , process: " + timer.path.instance.id + " , task: " + timer.task.name);
}
}
}
}
else
{
List<WorkflowInstance> workflows = workflowService.getActiveWorkflows(id);
for (WorkflowInstance workflow : workflows)
{
List<WorkflowTimer> timers = workflowService.getTimers(workflow.id);
for (WorkflowTimer timer : timers)
{
out.println("id: " + timer.id + " , name: " + timer.name + " , due date: " + timer.dueDate + " , path: " + timer.path.id + " , node: " + timer.path.node.name + " , process: " + timer.path.instance.id + " , task: " + timer.task.name);
}
}
}
}
else if (command[1].equals("my"))
{
if (command.length != 3)
@@ -550,6 +615,144 @@ public class WorkflowInterpreter
out.println("context: " + workflow.context);
out.println("package: " + workflow.workflowPackage);
}
else if (command[1].equals("path"))
{
if (command.length != 3)
{
return "Syntax Error.\n";
}
Map<QName, Serializable> properties = workflowService.getPathProperties(command[2]);
out.println("path: " + command[1]);
out.println("properties: " + properties.size());
for (Map.Entry<QName, Serializable> prop : properties.entrySet())
{
out.println(" " + prop.getKey() + " = " + prop.getValue());
}
}
else
{
return "Syntax Error.\n";
}
}
else if (command[0].equals("query"))
{
if (command.length < 2)
{
return "Syntax Error.\n";
}
if (command[1].equals("task"))
{
// build query
WorkflowTaskQuery query = new WorkflowTaskQuery();
Map<QName, Object> taskProps = new HashMap<QName, Object>();
Map<QName, Object> procProps = new HashMap<QName, Object>();
for (int i = 2; i < command.length; i++)
{
String[] predicate = command[i].split("=");
if (predicate.length == 1)
{
return "Syntax Error.\n";
}
String[] predicateName = predicate[0].split("\\.");
if (predicateName.length == 1)
{
if (predicate[0].equals("taskId"))
{
query.setTaskId(predicate[1]);
}
else if (predicate[0].equals("taskState"))
{
WorkflowTaskState state = WorkflowTaskState.valueOf(predicate[1]);
if (state == null)
{
return "Syntax Error. Unknown task state\n";
}
query.setTaskState(state);
}
else if (predicate[0].equals("taskName"))
{
query.setTaskName(QName.createQName(predicate[1], namespaceService));
}
else if (predicate[0].equals("taskActor"))
{
query.setActorId(predicate[1]);
}
else if (predicate[0].equals("processId"))
{
query.setProcessId(predicate[1]);
}
else if (predicate[0].equals("processName"))
{
query.setProcessName(QName.createQName(predicate[1], namespaceService));
}
else if (predicate[0].equals("processActive"))
{
Boolean active = Boolean.valueOf(predicate[1]);
query.setActive(active);
}
else if (predicate[0].equals("orderBy"))
{
String[] orderBy = predicate[1].split(",");
WorkflowTaskQuery.OrderBy[] queryOrderBy = new WorkflowTaskQuery.OrderBy[orderBy.length];
for (int iOrderBy = 0; iOrderBy < orderBy.length; iOrderBy++)
{
queryOrderBy[iOrderBy] = WorkflowTaskQuery.OrderBy.valueOf(orderBy[iOrderBy]);
if (queryOrderBy[iOrderBy] == null)
{
return "Syntax Error. Unknown orderBy.\n";
}
}
query.setOrderBy(queryOrderBy);
}
else
{
return "Syntax Error. Unknown query predicate.\n";
}
}
else if (predicateName.length == 2)
{
if (predicateName[0].equals("task"))
{
taskProps.put(QName.createQName(predicateName[1], namespaceService), predicate[1]);
}
else if (predicateName[0].equals("process"))
{
procProps.put(QName.createQName(predicateName[1], namespaceService), predicate[1]);
}
else
{
return "Syntax Error. Unknown query predicate.\n";
}
}
else
{
return "Syntax Error.\n";
}
}
if (taskProps.size() > 0)
{
query.setTaskCustomProps(taskProps);
}
if (procProps.size() > 0)
{
query.setProcessCustomProps(procProps);
}
// execute query
List<WorkflowTask> tasks = workflowService.queryTasks(query);
out.println("found " + tasks.size() + " tasks.");
for (WorkflowTask task : tasks)
{
out.println("task id: " + task.id + " , name: " + task.name + " , properties: " + task.properties.size() + ", process id: " + task.path.instance);
}
}
else
{
return "Syntax Error.\n";
@@ -591,14 +794,38 @@ public class WorkflowInterpreter
}
if (command[1].equals("definition"))
{
if (command.length != 3)
if (command.length == 3)
{
workflowService.undeployDefinition(command[2]);
currentWorkflowDef = null;
currentPath = null;
out.print(executeCommand("show definitions"));
}
else if (command.length == 4)
{
if (command[2].equals("name"))
{
out.print("undeploying...");
List<WorkflowDefinition> defs = workflowService.getAllDefinitionsByName(command[3]);
for (WorkflowDefinition def: defs)
{
workflowService.undeployDefinition(def.id);
out.print(" v" + def.version);
}
out.println("");
currentWorkflowDef = null;
currentPath = null;
out.print(executeCommand("show definitions all"));
}
else
{
return "Syntax Error.\n";
}
}
else
{
return "Syntax Error.\n";
}
workflowService.undeployDefinition(command[2]);
currentWorkflowDef = null;
currentPath = null;
out.print(executeCommand("show definitions"));
}
else
{
@@ -610,7 +837,7 @@ public class WorkflowInterpreter
{
if (command.length == 1)
{
out.println("definition: " + ((currentWorkflowDef == null) ? "None" : currentWorkflowDef.id + " , name: " + currentWorkflowDef.title));
out.println("definition: " + ((currentWorkflowDef == null) ? "None" : currentWorkflowDef.id + " , name: " + currentWorkflowDef.title + " , version: " + currentWorkflowDef.version));
out.println("workflow: " + ((currentPath == null) ? "None" : currentPath.instance.id + " , active: " + currentPath.instance.active));
out.println("path: " + ((currentPath == null) ? "None" : currentPath.id + " , node: " + currentPath.node.title));
}
@@ -748,6 +975,17 @@ public class WorkflowInterpreter
out.print(interpretCommand("show transitions"));
}
else if (command[0].equals("event"))
{
if (command.length < 3)
{
return "Syntax Error.\n";
}
WorkflowPath path = workflowService.fireEvent(command[1], command[2]);
out.println("event " + command[2] + " fired - path id: " + path.id);
out.print(interpretCommand("show transitions"));
}
else if (command[0].equals("end"))
{
if (command.length < 3)
@@ -769,7 +1007,6 @@ public class WorkflowInterpreter
}
workflowService.cancelWorkflow(workflowId);
out.println("workflow " + workflowId + " cancelled.");
out.print(interpretCommand("show transitions"));
}
else
{
@@ -807,7 +1044,7 @@ public class WorkflowInterpreter
}
if (command[3].equals("imeanit"))
{
for (WorkflowDefinition def : workflowService.getDefinitions())
for (WorkflowDefinition def : workflowService.getAllDefinitions())
{
List<WorkflowInstance> workflows = workflowService.getActiveWorkflows(def.id);
for (WorkflowInstance workflow : workflows)

View File

@@ -44,6 +44,7 @@ import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskQuery;
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
import org.alfresco.service.cmr.workflow.WorkflowTimer;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -158,7 +159,22 @@ public class WorkflowServiceImpl implements WorkflowService
}
return Collections.unmodifiableList(definitions);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.workflow.WorkflowService#getAllDefinitions()
*/
public List<WorkflowDefinition> getAllDefinitions()
{
List<WorkflowDefinition> definitions = new ArrayList<WorkflowDefinition>(10);
String[] ids = registry.getWorkflowComponents();
for (String id: ids)
{
WorkflowComponent component = registry.getWorkflowComponent(id);
definitions.addAll(component.getAllDefinitions());
}
return Collections.unmodifiableList(definitions);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.workflow.WorkflowService#getDefinitionById(java.lang.String)
*/
@@ -179,6 +195,16 @@ public class WorkflowServiceImpl implements WorkflowService
return component.getDefinitionByName(workflowName);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.workflow.WorkflowService#getAllDefinitionsByName(java.lang.String)
*/
public List<WorkflowDefinition> getAllDefinitionsByName(String workflowName)
{
String engineId = BPMEngineRegistry.getEngineId(workflowName);
WorkflowComponent component = getWorkflowComponent(engineId);
return component.getAllDefinitionsByName(workflowName);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.workflow.WorkflowService#getDefinitionImage(java.lang.String)
*/
@@ -243,6 +269,16 @@ public class WorkflowServiceImpl implements WorkflowService
return component.getWorkflowPaths(workflowId);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.workflow.WorkflowService#getPathProperties(java.lang.String)
*/
public Map<QName, Serializable> getPathProperties(String pathId)
{
String engineId = BPMEngineRegistry.getEngineId(pathId);
WorkflowComponent component = getWorkflowComponent(engineId);
return component.getPathProperties(pathId);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.workflow.WorkflowService#cancelWorkflow(java.lang.String)
*/
@@ -281,6 +317,26 @@ public class WorkflowServiceImpl implements WorkflowService
return component.signal(pathId, transition);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.workflow.WorkflowService#fireEvent(java.lang.String, java.lang.String)
*/
public WorkflowPath fireEvent(String pathId, String event)
{
String engineId = BPMEngineRegistry.getEngineId(pathId);
WorkflowComponent component = getWorkflowComponent(engineId);
return component.fireEvent(pathId, event);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.workflow.WorkflowService#getTimers(java.lang.String)
*/
public List<WorkflowTimer> getTimers(String workflowId)
{
String engineId = BPMEngineRegistry.getEngineId(workflowId);
WorkflowComponent component = getWorkflowComponent(engineId);
return component.getTimers(workflowId);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.workflow.WorkflowService#getTasksForWorkflowPath(java.lang.String)
*/

View File

@@ -31,8 +31,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
import java.util.zip.ZipInputStream;
@@ -70,6 +70,7 @@ import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
import org.alfresco.service.cmr.workflow.WorkflowTaskQuery;
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
import org.alfresco.service.cmr.workflow.WorkflowTimer;
import org.alfresco.service.cmr.workflow.WorkflowTransition;
import org.alfresco.service.namespace.NamespaceException;
import org.alfresco.service.namespace.NamespaceService;
@@ -91,11 +92,14 @@ import org.jbpm.context.exe.VariableInstance;
import org.jbpm.db.GraphSession;
import org.jbpm.db.TaskMgmtSession;
import org.jbpm.file.def.FileDefinition;
import org.jbpm.graph.def.Event;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.def.Transition;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import org.jbpm.job.Timer;
import org.jbpm.jpdl.par.ProcessArchive;
import org.jbpm.jpdl.xml.Problem;
import org.jbpm.taskmgmt.def.Task;
@@ -139,6 +143,14 @@ public class JBPMEngine extends BPMEngine
"where ti.actorId = :actorId " +
"and ti.isOpen = false " +
"and ti.end is not null";
// Note: jBPM query which is not provided out-of-the-box
// TODO: Check jBPMg future and get this implemented in jBPM
private final static String PROCESS_TIMERS_QUERY =
"select timer " +
"from org.jbpm.job.Timer timer " +
"where timer.processInstance = :process ";
// Workflow Path Seperators
private final static String WORKFLOW_PATH_SEPERATOR = "-";
@@ -363,6 +375,36 @@ public class JBPMEngine extends BPMEngine
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.WorkflowDefinitionComponent#getDefinitions()
*/
@SuppressWarnings("unchecked")
public List<WorkflowDefinition> getAllDefinitions()
{
try
{
return (List<WorkflowDefinition>)jbpmTemplate.execute(new JbpmCallback()
{
public Object doInJbpm(JbpmContext context)
{
GraphSession graphSession = context.getGraphSession();
List<ProcessDefinition> processDefs = (List<ProcessDefinition>)graphSession.findAllProcessDefinitions();
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)
*/
@@ -410,7 +452,38 @@ public class JBPMEngine extends BPMEngine
throw new WorkflowException("Failed to retrieve workflow definition '" + workflowName + "'", e);
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.WorkflowComponent#getAllDefinitionsByName(java.lang.String)
*/
@SuppressWarnings("unchecked")
public List<WorkflowDefinition> getAllDefinitionsByName(final String workflowName)
{
try
{
return (List<WorkflowDefinition>)jbpmTemplate.execute(new JbpmCallback()
{
@SuppressWarnings("synthetic-access")
public Object doInJbpm(JbpmContext context)
{
GraphSession graphSession = context.getGraphSession();
List<ProcessDefinition> processDefs = (List<ProcessDefinition>)graphSession.findAllProcessDefinitionVersions(createLocalId(workflowName));
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 all definitions for workflow '" + workflowName + "'", e);
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.WorkflowComponent#getDefinitionImage(java.lang.String)
*/
@@ -630,6 +703,55 @@ public class JBPMEngine extends BPMEngine
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.WorkflowComponent#getPathProperties(java.lang.String)
*/
@SuppressWarnings("unchecked")
public Map<QName, Serializable> getPathProperties(final String pathId)
{
try
{
return (Map<QName, Serializable>) jbpmTemplate.execute(new JbpmCallback()
{
public Map<QName, Serializable> doInJbpm(JbpmContext context)
{
// retrieve jBPM token for workflow position
GraphSession graphSession = context.getGraphSession();
Token token = getWorkflowToken(graphSession, pathId);
ContextInstance instanceContext = token.getProcessInstance().getContextInstance();
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(10);
while (token != null)
{
TokenVariableMap varMap = instanceContext.getTokenVariableMap(token);
if (varMap != null)
{
Map<String, Object> tokenVars = varMap.getVariablesLocally();
for (Map.Entry<String, Object> entry : tokenVars.entrySet())
{
String key = entry.getKey();
QName qname = mapNameToQName(key);
if (!properties.containsKey(key))
{
Serializable value = convertValue(entry.getValue());
properties.put(qname, value);
}
}
}
token = token.getParent();
}
return properties;
}
});
}
catch(JbpmException e)
{
throw new WorkflowException("Failed to retrieve properties of path '" + pathId + "'", e);
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.WorkflowComponent#cancelWorkflow(java.lang.String)
*/
@@ -739,6 +861,78 @@ public class JBPMEngine extends BPMEngine
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.WorkflowComponent#fireEvent(java.lang.String, java.lang.String)
*/
public WorkflowPath fireEvent(final String pathId, final String event)
{
try
{
return (WorkflowPath) jbpmTemplate.execute(new JbpmCallback()
{
@SuppressWarnings("unchecked")
public Object doInJbpm(JbpmContext context)
{
// NOTE: Do not allow jBPM built-in events to be fired
if (event.equals(Event.EVENTTYPE_AFTER_SIGNAL) ||
event.equals(Event.EVENTTYPE_BEFORE_SIGNAL) ||
event.equals(Event.EVENTTYPE_NODE_ENTER) ||
event.equals(Event.EVENTTYPE_NODE_LEAVE) ||
event.equals(Event.EVENTTYPE_PROCESS_END) ||
event.equals(Event.EVENTTYPE_PROCESS_START) ||
event.equals(Event.EVENTTYPE_SUBPROCESS_CREATED) ||
event.equals(Event.EVENTTYPE_SUBPROCESS_END) ||
event.equals(Event.EVENTTYPE_SUPERSTATE_ENTER) ||
event.equals(Event.EVENTTYPE_SUPERSTATE_LEAVE) ||
event.equals(Event.EVENTTYPE_TASK_ASSIGN) ||
event.equals(Event.EVENTTYPE_TASK_CREATE) ||
event.equals(Event.EVENTTYPE_TASK_END) ||
event.equals(Event.EVENTTYPE_TASK_START) ||
event.equals(Event.EVENTTYPE_TIMER) ||
event.equals(Event.EVENTTYPE_TRANSITION))
{
throw new WorkflowException("Event " + event + " is not a valid event");
}
// retrieve jBPM token for workflow position
GraphSession graphSession = context.getGraphSession();
Token token = getWorkflowToken(graphSession, pathId);
ExecutionContext executionContext = new ExecutionContext(token);
TaskMgmtSession taskSession = context.getTaskMgmtSession();
List<TaskInstance> tasks = taskSession.findTaskInstancesByToken(token.getId());
if (tasks.size() == 0)
{
// fire the event against current node for the token
Node node = token.getNode();
node.fireEvent(event, executionContext);
}
else
{
// fire the event against tasks associated with the node
// NOTE: this will also propagate the event to the node
for (TaskInstance task : tasks)
{
executionContext.setTaskInstance(task);
task.getTask().fireEvent(event, executionContext);
}
}
// save
ProcessInstance processInstance = token.getProcessInstance();
context.save(processInstance);
// return new workflow path
return createWorkflowPath(token);
}
});
}
catch(JbpmException e)
{
throw new WorkflowException("Failed to fire event '" + event + "' on workflow path '" + pathId + "'", e);
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.WorkflowComponent#getTasksForWorkflowPath(java.lang.String)
*/
@@ -772,6 +966,44 @@ public class JBPMEngine extends BPMEngine
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.WorkflowComponent#getTimers(java.lang.String)
*/
@SuppressWarnings("unchecked")
public List<WorkflowTimer> getTimers(final String workflowId)
{
try
{
return (List<WorkflowTimer>) jbpmTemplate.execute(new JbpmCallback()
{
public List<WorkflowTimer> doInJbpm(JbpmContext context)
{
// retrieve process
GraphSession graphSession = context.getGraphSession();
ProcessInstance process = getProcessInstance(graphSession, workflowId);
// retrieve timers for process
Session session = context.getSession();
Query query = session.createQuery(PROCESS_TIMERS_QUERY);
query.setEntity("process", process);
List<Timer> timers = query.list();
// convert timers to appropriate service response format
List<WorkflowTimer> workflowTimers = new ArrayList<WorkflowTimer>(timers.size());
for (Timer timer : timers)
{
WorkflowTimer workflowTimer = createWorkflowTimer(timer);
workflowTimers.add(workflowTimer);
}
return workflowTimers;
}
});
}
catch(JbpmException e)
{
throw new JbpmException("Couldn't get timers for process '" + workflowId + "'", e);
}
}
//
// Task Management ...
@@ -1562,30 +1794,8 @@ public class JBPMEngine extends BPMEngine
// add variable, only if part of task definition or locally defined on task
if (taskProperties.containsKey(qname) || taskAssocs.containsKey(qname) || instance.hasVariableLocally(key))
{
Object value = entry.getValue();
//
// perform data conversions
//
// Convert Nodes to NodeRefs
if (value instanceof JBPMNode)
{
value = ((JBPMNode)value).getNodeRef();
}
else if (value instanceof JBPMNodeList)
{
JBPMNodeList nodes = (JBPMNodeList)value;
List<NodeRef> nodeRefs = new ArrayList<NodeRef>(nodes.size());
for (JBPMNode node : nodes)
{
nodeRefs.add(node.getNodeRef());
}
value = (Serializable)nodeRefs;
}
// place task variable in map to return
properties.put(qname, (Serializable)value);
Serializable value = convertValue(entry.getValue());
properties.put(qname, value);
}
}
@@ -1982,6 +2192,45 @@ public class JBPMEngine extends BPMEngine
return (missingProps == null) ? null : missingProps.toArray(new QName[missingProps.size()]);
}
/**
* Convert a jBPM Value to an Alfresco value
*
* @param value jBPM value
* @return alfresco value
*/
private Serializable convertValue(Object value)
{
Serializable alfValue = null;
if (value == null)
{
// NOOP
}
else if (value instanceof JBPMNode)
{
alfValue = ((JBPMNode)value).getNodeRef();
}
else if (value instanceof JBPMNodeList)
{
JBPMNodeList nodes = (JBPMNodeList)value;
List<NodeRef> nodeRefs = new ArrayList<NodeRef>(nodes.size());
for (JBPMNode node : nodes)
{
nodeRefs.add(node.getNodeRef());
}
alfValue = (Serializable)nodeRefs;
}
else if (value instanceof Serializable)
{
alfValue = (Serializable)value;
}
else
{
throw new WorkflowException("Unable to convert jBPM value " + value + " to Alfresco Value - not serializable");
}
return alfValue;
}
/**
* Convert a Repository association to JBPMNodeList or JBPMNode
*
@@ -2187,15 +2436,7 @@ public class JBPMEngine extends BPMEngine
workflowNode.name = node.getName();
workflowNode.title = getLabel(processName + ".node." + workflowNode.name, TITLE_LABEL, workflowNode.name);
workflowNode.description = getLabel(processName + ".node." + workflowNode.name, DESC_LABEL, workflowNode.title);
if (node instanceof HibernateProxy)
{
Node realNode = (Node)((HibernateProxy)node).getHibernateLazyInitializer().getImplementation();
workflowNode.type = realNode.getClass().getSimpleName();
}
else
{
workflowNode.type = node.getClass().getSimpleName();
}
workflowNode.type = getRealNode(node).getClass().getSimpleName();
// TODO: Is there a formal way of determing if task node?
workflowNode.isTaskNode = workflowNode.type.equals("TaskNode");
List transitions = node.getLeavingTransitions();
@@ -2358,6 +2599,22 @@ public class JBPMEngine extends BPMEngine
return deployment;
}
/**
* Creates a Workflow Timer
* @param timer jBPM Timer
* @return workflow timer
*/
protected WorkflowTimer createWorkflowTimer(Timer timer)
{
WorkflowTimer workflowTimer = new WorkflowTimer();
workflowTimer.id = createGlobalId(new Long(timer.getId()).toString());
workflowTimer.name = timer.getName();
workflowTimer.dueDate = timer.getDueDate();
workflowTimer.path = createWorkflowPath(timer.getToken());
workflowTimer.task = createWorkflowTask(timer.getTaskInstance());
return workflowTimer;
}
/**
* Get the Workflow Task State for the specified JBoss JBPM Task
*
@@ -2376,4 +2633,23 @@ public class JBPMEngine extends BPMEngine
}
}
/**
* Helper to retrieve the real jBPM Node
*
* @param node Node
* @return real Node (i.e. the one that's not a Hibernate proxy)
*/
private Node getRealNode(Node node)
{
if (node instanceof HibernateProxy)
{
Node realNode = (Node)((HibernateProxy)node).getHibernateLazyInitializer().getImplementation();
return realNode;
}
else
{
return node;
}
}
}

View File

@@ -97,13 +97,21 @@ public interface WorkflowService
public void undeployDefinition(String workflowDefinitionId);
/**
* Gets all deployed Workflow Definitions
* Gets latest deployed Workflow Definitions
*
* @return the deployed workflow definitions
* @return the latest deployed workflow definitions
*/
@Auditable
public List<WorkflowDefinition> getDefinitions();
/**
* Gets all deployed Workflow Definitions (with all previous versions)
*
* @return the deployed (and previous) workflow definitions
*/
@Auditable
public List<WorkflowDefinition> getAllDefinitions();
/**
* Gets a Workflow Definition by unique Id
*
@@ -114,7 +122,7 @@ public interface WorkflowService
public WorkflowDefinition getDefinitionById(String workflowDefinitionId);
/**
* Gets a Workflow Definition by unique name
* Gets the latest Workflow Definition by unique name
*
* @param workflowName workflow name e.g. jbpm://review
* @return the deployed workflow definition (or null if not found)
@@ -122,6 +130,15 @@ public interface WorkflowService
@Auditable(parameters = {"workflowName"})
public WorkflowDefinition getDefinitionByName(String workflowName);
/**
* Gets all (including previous) Workflow Definitions for the given unique name
*
* @param workflowName workflow name e.g. jbpm://review
* @return the deployed workflow definition (or null if not found)
*/
@Auditable(parameters = {"workflowName"})
public List<WorkflowDefinition> getAllDefinitionsByName(String workflowName);
/**
* Gets a graphical view of the Workflow Definition
*
@@ -184,6 +201,15 @@ public interface WorkflowService
@Auditable(parameters = {"workflowId"})
public List<WorkflowPath> getWorkflowPaths(String workflowId);
/**
* Gets the properties associated with the specified path (and parent paths)
*
* @param pathId workflow path id
* @return map of path properties
*/
@Auditable(parameters = {"pathId"})
public Map<QName, Serializable> getPathProperties(String pathId);
/**
* Cancel an "in-fligth" Workflow instance
*
@@ -215,6 +241,16 @@ public interface WorkflowService
@Auditable(parameters = {"pathId", "transitionId"})
public WorkflowPath signal(String pathId, String transitionId);
/**
* Fire custom event against specified path
*
* @param pathId the workflow path to fire event on
* @param event name of event
* @return workflow path (it may have been updated as a result of firing the event
*/
@Auditable(parameters = {"pathId", "event"})
public WorkflowPath fireEvent(String pathId, String event);
/**
* Gets all Tasks associated with the specified path
*
@@ -223,8 +259,21 @@ public interface WorkflowService
*/
@Auditable(parameters = {"pathId"})
public List<WorkflowTask> getTasksForWorkflowPath(String pathId);
//
// Workflow Timer Management
//
/**
* Gets all active timers for the specified workflow
*
* @return the list of active timers
*/
@Auditable(parameters = {"workflowId"})
public List<WorkflowTimer> getTimers(String workflowId);
//
// Task Management
//
@@ -263,7 +312,7 @@ public interface WorkflowService
* @param query the filter by which tasks are queried
* @return the list of tasks matching the specified query
*/
@Auditable(parameters = {"filter"})
@Auditable(parameters = {"query"})
public List<WorkflowTask> queryTasks(WorkflowTaskQuery query);
/**

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.service.cmr.workflow;
import java.util.Date;
public class WorkflowTimer
{
/** Timer Id */
public String id;
/** Transition Name */
public String name;
/** Associated Workflow Path */
public WorkflowPath path;
/** Associated Workflow Task (if any) */
public WorkflowTask task;
/** Due Date */
public Date dueDate;
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
public String toString()
{
return "WorkflowTimer[id=" + id + ",name=" + name + ",dueDate=" + dueDate + ",path=" + path + ",task=" + task + "]";
}
}