Merged 5.2.N (5.2.1) to HEAD (5.2)

125783 rmunteanu: Merged 5.1.N (5.1.2) to 5.2.N (5.2.1)
      125605 rmunteanu: Merged 5.1.1 (5.1.1) to 5.1.N (5.1.2)
         125498 slanglois: MNT-16155 Update source headers - remove svn:eol-style property on Java and JSP source files


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@127809 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2016-06-03 16:45:04 +00:00
parent 91eb2644ad
commit 12769c2923
830 changed files with 142534 additions and 142534 deletions

View File

@@ -1,87 +1,87 @@
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
* @author Nick Smith
*/
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;
}
/**
* @return the engineId
*/
protected String getEngineId()
{
return engineId;
}
/**
* {@inheritDoc}
*/
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
*/
public 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
*/
public String createLocalId(String globalId)
{
return BPMEngineRegistry.getLocalId(globalId);
}
}
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
* @author Nick Smith
*/
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;
}
/**
* @return the engineId
*/
protected String getEngineId()
{
return engineId;
}
/**
* {@inheritDoc}
*/
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
*/
public 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
*/
public String createLocalId(String globalId)
{
return BPMEngineRegistry.getLocalId(globalId);
}
}

View File

@@ -1,232 +1,232 @@
package org.alfresco.repo.workflow;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.service.cmr.workflow.WorkflowAdminService;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.util.collections.CollectionUtils;
import org.alfresco.util.collections.Filter;
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 WorkflowAdminService workflowAdminService;
private Map<String, WorkflowComponent> workflowComponents;
private Map<String, TaskComponent> taskComponents;
/**
* Construct
*/
public BPMEngineRegistry()
{
workflowComponents = new HashMap<String, WorkflowComponent>();
taskComponents = new HashMap<String, TaskComponent>();
}
/**
* Sets the workflow admin service
*
* @param workflowAdminService the workflow admin service
*/
public void setWorkflowAdminService(WorkflowAdminService workflowAdminService)
{
this.workflowAdminService = workflowAdminService;
}
/**
* 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.isDebugEnabled())
logger.debug("Registered Workflow Component '" + engineId + "' (" + engine.getClass() + ")");
}
/**
* Gets all registered Workflow Components
*
* @return array of engine ids
*/
public String[] getWorkflowComponents()
{
return getComponents(workflowComponents.keySet());
}
/**
* Gets a specific BPM Engine Workflow Component
*
* @param engineId engine id
* @return the Workflow Component
*/
public WorkflowComponent getWorkflowComponent(String engineId)
{
if(false == workflowAdminService.isEngineEnabled(engineId))
{
if(logger.isDebugEnabled())
{
logger.debug("Ignoring disabled WorkflowComponent: "+engineId);
}
return null;
}
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.isDebugEnabled())
logger.debug("Registered Task Component '" + engineId + "' (" + engine.getClass() + ")");
}
/**
* Gets all registered Task Components
*
* @return array of engine ids
*/
public String[] getTaskComponents()
{
return getComponents(taskComponents.keySet());
}
private String[] getComponents(Set<String> components)
{
List<String> filtered = CollectionUtils.filter(components, new Filter<String>()
{
public Boolean apply(String engineId)
{
return workflowAdminService.isEngineEnabled(engineId);
}
});
return filtered.toArray(new String[filtered.size()]);
}
/**
* Gets a specific BPM Engine Task Component
*
* @param engineId engine id
* @return the Workflow Component
*/
public TaskComponent getTaskComponent(String engineId)
{
if(false == workflowAdminService.isEngineEnabled(engineId))
{
if(logger.isDebugEnabled())
{
logger.debug("Ignoring disabled TaskComponent: "+engineId);
}
return null;
}
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];
}
/**
* Returns <code>true</code> if the globalId parameter is a valid global Id
* for the given engineId.
*
* @param globalId String
* @param engineId String
* @return boolean
*/
public static boolean isGlobalId(String globalId, String engineId)
{
return globalId.startsWith(engineId+ID_SEPERATOR);
}
}
package org.alfresco.repo.workflow;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.service.cmr.workflow.WorkflowAdminService;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.util.collections.CollectionUtils;
import org.alfresco.util.collections.Filter;
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 WorkflowAdminService workflowAdminService;
private Map<String, WorkflowComponent> workflowComponents;
private Map<String, TaskComponent> taskComponents;
/**
* Construct
*/
public BPMEngineRegistry()
{
workflowComponents = new HashMap<String, WorkflowComponent>();
taskComponents = new HashMap<String, TaskComponent>();
}
/**
* Sets the workflow admin service
*
* @param workflowAdminService the workflow admin service
*/
public void setWorkflowAdminService(WorkflowAdminService workflowAdminService)
{
this.workflowAdminService = workflowAdminService;
}
/**
* 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.isDebugEnabled())
logger.debug("Registered Workflow Component '" + engineId + "' (" + engine.getClass() + ")");
}
/**
* Gets all registered Workflow Components
*
* @return array of engine ids
*/
public String[] getWorkflowComponents()
{
return getComponents(workflowComponents.keySet());
}
/**
* Gets a specific BPM Engine Workflow Component
*
* @param engineId engine id
* @return the Workflow Component
*/
public WorkflowComponent getWorkflowComponent(String engineId)
{
if(false == workflowAdminService.isEngineEnabled(engineId))
{
if(logger.isDebugEnabled())
{
logger.debug("Ignoring disabled WorkflowComponent: "+engineId);
}
return null;
}
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.isDebugEnabled())
logger.debug("Registered Task Component '" + engineId + "' (" + engine.getClass() + ")");
}
/**
* Gets all registered Task Components
*
* @return array of engine ids
*/
public String[] getTaskComponents()
{
return getComponents(taskComponents.keySet());
}
private String[] getComponents(Set<String> components)
{
List<String> filtered = CollectionUtils.filter(components, new Filter<String>()
{
public Boolean apply(String engineId)
{
return workflowAdminService.isEngineEnabled(engineId);
}
});
return filtered.toArray(new String[filtered.size()]);
}
/**
* Gets a specific BPM Engine Task Component
*
* @param engineId engine id
* @return the Workflow Component
*/
public TaskComponent getTaskComponent(String engineId)
{
if(false == workflowAdminService.isEngineEnabled(engineId))
{
if(logger.isDebugEnabled())
{
logger.debug("Ignoring disabled TaskComponent: "+engineId);
}
return null;
}
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];
}
/**
* Returns <code>true</code> if the globalId parameter is a valid global Id
* for the given engineId.
*
* @param globalId String
* @param engineId String
* @return boolean
*/
public static boolean isGlobalId(String globalId, String engineId)
{
return globalId.startsWith(engineId+ID_SEPERATOR);
}
}

View File

@@ -1,144 +1,144 @@
package org.alfresco.repo.workflow;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.WorkflowPath;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
/**
* Simple workflow action executor
*
* @author David Caruana
*/
public class StartWorkflowActionExecuter extends ActionExecuterAbstractBase
{
public static final String NAME = "start-workflow";
public static final String PARAM_WORKFLOW_NAME = "workflowName";
public static final String PARAM_END_START_TASK = "endStartTask";
public static final String PARAM_START_TASK_TRANSITION = "startTaskTransition";
// action dependencies
private NamespaceService namespaceService;
private WorkflowService workflowService;
private NodeService nodeService;
/**
* @param namespaceService NamespaceService
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param nodeService NodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param workflowService 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)));
paramList.add(new ParameterDefinitionImpl(PARAM_END_START_TASK, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_END_START_TASK)));
paramList.add(new ParameterDefinitionImpl(PARAM_START_TASK_TRANSITION, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_START_TASK_TRANSITION)));
// TODO: start task node parameter
}
/* (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, WorkflowModel.ASSOC_PACKAGE_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);
}
}
// provide a default context, if one is not specified
Serializable context = workflowParameters.get(WorkflowModel.PROP_CONTEXT);
if (context == null)
{
workflowParameters.put(WorkflowModel.PROP_CONTEXT, childAssoc.getParentRef());
}
// start the workflow
WorkflowPath path = workflowService.startWorkflow(def.getId(), workflowParameters);
// determine whether to auto-end the start task
Boolean endStartTask = (Boolean)ruleAction.getParameterValue(PARAM_END_START_TASK);
String startTaskTransition = (String)ruleAction.getParameterValue(PARAM_START_TASK_TRANSITION);
endStartTask = (endStartTask == null) ? true : false;
// auto-end the start task with the provided transition (if one)
if (endStartTask)
{
List<WorkflowTask> tasks = workflowService.getTasksForWorkflowPath(path.getId());
for (WorkflowTask task : tasks)
{
workflowService.endTask(task.getId(), startTaskTransition);
}
}
}
}
package org.alfresco.repo.workflow;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.WorkflowPath;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
/**
* Simple workflow action executor
*
* @author David Caruana
*/
public class StartWorkflowActionExecuter extends ActionExecuterAbstractBase
{
public static final String NAME = "start-workflow";
public static final String PARAM_WORKFLOW_NAME = "workflowName";
public static final String PARAM_END_START_TASK = "endStartTask";
public static final String PARAM_START_TASK_TRANSITION = "startTaskTransition";
// action dependencies
private NamespaceService namespaceService;
private WorkflowService workflowService;
private NodeService nodeService;
/**
* @param namespaceService NamespaceService
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param nodeService NodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param workflowService 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)));
paramList.add(new ParameterDefinitionImpl(PARAM_END_START_TASK, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_END_START_TASK)));
paramList.add(new ParameterDefinitionImpl(PARAM_START_TASK_TRANSITION, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_START_TASK_TRANSITION)));
// TODO: start task node parameter
}
/* (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, WorkflowModel.ASSOC_PACKAGE_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);
}
}
// provide a default context, if one is not specified
Serializable context = workflowParameters.get(WorkflowModel.PROP_CONTEXT);
if (context == null)
{
workflowParameters.put(WorkflowModel.PROP_CONTEXT, childAssoc.getParentRef());
}
// start the workflow
WorkflowPath path = workflowService.startWorkflow(def.getId(), workflowParameters);
// determine whether to auto-end the start task
Boolean endStartTask = (Boolean)ruleAction.getParameterValue(PARAM_END_START_TASK);
String startTaskTransition = (String)ruleAction.getParameterValue(PARAM_START_TASK_TRANSITION);
endStartTask = (endStartTask == null) ? true : false;
// auto-end the start task with the provided transition (if one)
if (endStartTask)
{
List<WorkflowTask> tasks = workflowService.getTasksForWorkflowPath(path.getId());
for (WorkflowTask task : tasks)
{
workflowService.endTask(task.getId(), startTaskTransition);
}
}
}
}

View File

@@ -1,133 +1,133 @@
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.WorkflowTaskQuery;
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
* @param lazyInitialization hint in order to return partially-initialized entities
* @return the list of assigned tasks
*/
public List<WorkflowTask> getAssignedTasks(String authority, WorkflowTaskState state, boolean lazyInitialization);
/**
* Gets the pooled tasks available to the specified authority
*
* @param authorities the list of authorities
* @param lazyInitialization hint in order to return partially-initialized entities
* @return the list of pooled tasks
*/
public List<WorkflowTask> getPooledTasks(List<String> authorities, boolean lazyInitialization);
/**
* @deprecated Use overloaded method with the {@code sameSession} parameter
* (this method defaults the parameter to {@code false}).
*/
public List<WorkflowTask> queryTasks(WorkflowTaskQuery query);
/**
* Query for tasks
*
* Hint: use {@link WorkflowTaskQuery} setLimit() method to limit the number
* of processed items if you don't really need to go through all of them
*
* @param query
* the filter by which tasks are queried
* @param sameSession
* indicates that the returned {@link WorkflowTask} elements will
* be used in the same session. If {@code true}, the returned
* List will be a lazy loaded list providing greater performance.
* @return the list of tasks matching the specified query
*/
public List<WorkflowTask> queryTasks(final WorkflowTaskQuery query, boolean sameSession);
/**
* Count the number of active tasks that match the given query.
*
* @param query the filter by which tasks are queried
* @return number of matching tasks.
*/
public long countTasks(final WorkflowTaskQuery query);
/**
* 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 String
* @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 transitionId the task transition id to take on completion (or null, for the default transition)
* @return the updated task
*/
public WorkflowTask endTask(String taskId, String transitionId);
/**
* Gets all active timers for the specified workflow
*
* @return the list of active timers
*/
public WorkflowTask getStartTask(String workflowInstanceId);
/**
* Gets all start tasks for the specified workflow
*
* @return the list of start tasks
*/
public List<WorkflowTask> getStartTasks(final List<String> workflowInstanceIds, final boolean sameSession);
}
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.WorkflowTaskQuery;
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
* @param lazyInitialization hint in order to return partially-initialized entities
* @return the list of assigned tasks
*/
public List<WorkflowTask> getAssignedTasks(String authority, WorkflowTaskState state, boolean lazyInitialization);
/**
* Gets the pooled tasks available to the specified authority
*
* @param authorities the list of authorities
* @param lazyInitialization hint in order to return partially-initialized entities
* @return the list of pooled tasks
*/
public List<WorkflowTask> getPooledTasks(List<String> authorities, boolean lazyInitialization);
/**
* @deprecated Use overloaded method with the {@code sameSession} parameter
* (this method defaults the parameter to {@code false}).
*/
public List<WorkflowTask> queryTasks(WorkflowTaskQuery query);
/**
* Query for tasks
*
* Hint: use {@link WorkflowTaskQuery} setLimit() method to limit the number
* of processed items if you don't really need to go through all of them
*
* @param query
* the filter by which tasks are queried
* @param sameSession
* indicates that the returned {@link WorkflowTask} elements will
* be used in the same session. If {@code true}, the returned
* List will be a lazy loaded list providing greater performance.
* @return the list of tasks matching the specified query
*/
public List<WorkflowTask> queryTasks(final WorkflowTaskQuery query, boolean sameSession);
/**
* Count the number of active tasks that match the given query.
*
* @param query the filter by which tasks are queried
* @return number of matching tasks.
*/
public long countTasks(final WorkflowTaskQuery query);
/**
* 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 String
* @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 transitionId the task transition id to take on completion (or null, for the default transition)
* @return the updated task
*/
public WorkflowTask endTask(String taskId, String transitionId);
/**
* Gets all active timers for the specified workflow
*
* @return the list of active timers
*/
public WorkflowTask getStartTask(String workflowInstanceId);
/**
* Gets all start tasks for the specified workflow
*
* @return the list of start tasks
*/
public List<WorkflowTask> getStartTasks(final List<String> workflowInstanceIds, final boolean sameSession);
}

View File

@@ -1,134 +1,134 @@
package org.alfresco.repo.workflow;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A helper class for updating and transitioning {@link WorkflowTask
* WorkflowTasks}. This is a stateful object that accumulates a set of updates
* to a task and then commits all the updates when either the update() or
* transition() method is called.
*
* @since 3.4
* @author Nick Smith
*/
public class TaskUpdater
{
/** Logger */
private static final Log LOGGER = LogFactory.getLog(TaskUpdater.class);
private final String taskId;
private final WorkflowService workflowService;
private final PackageManager packageMgr;
private final Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
private final Map<QName, List<NodeRef>> add = new HashMap<QName, List<NodeRef>>();
private final Map<QName, List<NodeRef>> remove = new HashMap<QName, List<NodeRef>>();
public TaskUpdater(String taskId,
WorkflowService workflowService,
NodeService nodeService,
BehaviourFilter behaviourFilter)
{
this.taskId = taskId;
this.workflowService = workflowService;
this.packageMgr = new PackageManager(workflowService, nodeService, behaviourFilter, LOGGER);
}
public void addProperty(QName name, Serializable value)
{
properties.put(name, value);
}
public void addAssociation(QName name, List<NodeRef> value)
{
add.put(name, value);
}
public void removeAssociation(QName name, List<NodeRef> value)
{
remove.put(name, value);
}
public boolean changeAssociation(QName name, String nodeRefs, boolean isAdd)
{
List<NodeRef> value = NodeRef.getNodeRefs(nodeRefs, LOGGER);
if (value == null)
{
return false;
}
Map<QName, List<NodeRef>> map = getAssociationMap(isAdd);
if (map != null)
{
map.put(name, value);
return true;
}
return false;
}
/**
* @param isAdd boolean
* @return Map
*/
private Map<QName, List<NodeRef>> getAssociationMap(boolean isAdd)
{
Map<QName, List<NodeRef>> map = null;
if (isAdd)
{
map = add;
}
else
{
map = remove;
}
return map;
}
public void addPackageItems(List<NodeRef> items)
{
packageMgr.addItems(items);
}
public void removePackageItems(List<NodeRef> items)
{
packageMgr.removeItems(items);
}
public WorkflowTask transition()
{
return transition(null);
}
public WorkflowTask transition(String transitionId)
{
update();
return workflowService.endTask(taskId, transitionId);
}
public WorkflowTask update()
{
WorkflowTask task = workflowService.getTaskById(taskId);
NodeRef packageNode = task.getPath().getInstance().getWorkflowPackage();
packageMgr.update(packageNode);
WorkflowTask result = workflowService.updateTask(taskId, properties, add, remove);
properties.clear();
add.clear();
remove.clear();
return result;
}
}
package org.alfresco.repo.workflow;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A helper class for updating and transitioning {@link WorkflowTask
* WorkflowTasks}. This is a stateful object that accumulates a set of updates
* to a task and then commits all the updates when either the update() or
* transition() method is called.
*
* @since 3.4
* @author Nick Smith
*/
public class TaskUpdater
{
/** Logger */
private static final Log LOGGER = LogFactory.getLog(TaskUpdater.class);
private final String taskId;
private final WorkflowService workflowService;
private final PackageManager packageMgr;
private final Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
private final Map<QName, List<NodeRef>> add = new HashMap<QName, List<NodeRef>>();
private final Map<QName, List<NodeRef>> remove = new HashMap<QName, List<NodeRef>>();
public TaskUpdater(String taskId,
WorkflowService workflowService,
NodeService nodeService,
BehaviourFilter behaviourFilter)
{
this.taskId = taskId;
this.workflowService = workflowService;
this.packageMgr = new PackageManager(workflowService, nodeService, behaviourFilter, LOGGER);
}
public void addProperty(QName name, Serializable value)
{
properties.put(name, value);
}
public void addAssociation(QName name, List<NodeRef> value)
{
add.put(name, value);
}
public void removeAssociation(QName name, List<NodeRef> value)
{
remove.put(name, value);
}
public boolean changeAssociation(QName name, String nodeRefs, boolean isAdd)
{
List<NodeRef> value = NodeRef.getNodeRefs(nodeRefs, LOGGER);
if (value == null)
{
return false;
}
Map<QName, List<NodeRef>> map = getAssociationMap(isAdd);
if (map != null)
{
map.put(name, value);
return true;
}
return false;
}
/**
* @param isAdd boolean
* @return Map
*/
private Map<QName, List<NodeRef>> getAssociationMap(boolean isAdd)
{
Map<QName, List<NodeRef>> map = null;
if (isAdd)
{
map = add;
}
else
{
map = remove;
}
return map;
}
public void addPackageItems(List<NodeRef> items)
{
packageMgr.addItems(items);
}
public void removePackageItems(List<NodeRef> items)
{
packageMgr.removeItems(items);
}
public WorkflowTask transition()
{
return transition(null);
}
public WorkflowTask transition(String transitionId)
{
update();
return workflowService.endTask(taskId, transitionId);
}
public WorkflowTask update()
{
WorkflowTask task = workflowService.getTaskById(taskId);
NodeRef packageNode = task.getPath().getInstance().getWorkflowPackage();
packageMgr.update(packageNode);
WorkflowTask result = workflowService.updateTask(taskId, properties, add, remove);
properties.clear();
add.clear();
remove.clear();
return result;
}
}

View File

@@ -1,133 +1,133 @@
package org.alfresco.repo.workflow;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.alfresco.service.cmr.workflow.WorkflowAdminService;
/**
* Default implementation of the workflow admin service.
*
* @author Gavin Cornwell
* @author Nick Smith
* @since 4.0
*/
public class WorkflowAdminServiceImpl implements WorkflowAdminService
{
public static final String NAME = "workflowAdminService";
public static final String ENGINE = "engineId";
public static final String ENABLED = "enabled";
public static final String VISIBLE = "visible";
private Set<String> enabledEngines = new HashSet<String>();
private Set<String> visibleEngines = new HashSet<String>();
/**
* {@inheritDoc}
*/
public boolean isEngineEnabled(String engineId)
{
return enabledEngines.contains(engineId);
}
/**
* {@inheritDoc}
*/
public void setEngineEnabled(String engineId, boolean isEnabled)
{
if(isEnabled)
{
enabledEngines.add(engineId);
}
else
{
enabledEngines.remove(engineId);
}
}
/**
* {@inheritDoc}
*/
public boolean isEngineVisible(String engineId)
{
return isEngineEnabled(engineId) && visibleEngines.contains(engineId);
}
/**
* {@inheritDoc}
*/
public void setEngineVisibility(String engineId, boolean isVisible)
{
if(isVisible)
{
visibleEngines.add(engineId);
}
else
{
visibleEngines.remove(engineId);
}
}
/**
* Setter for Spring
* @param engines All engine Ids to enable.
*/
public void setEnabledEngines(Collection<String> engines)
{
if(false == enabledEngines.isEmpty())
{
enabledEngines.clear();
}
enabledEngines.addAll(engines);
}
/**
* @return the enabledEngines
*/
public Set<String> getEnabledEngines()
{
return new HashSet<String>(enabledEngines);
}
/**
* Setter for Spring.
* @param engines All engineIds to set visible.
*/
public void setVisibleEngines(Collection<String> engines)
{
if(false == visibleEngines.isEmpty())
{
visibleEngines.clear();
}
visibleEngines.addAll(engines);
}
/**
* @return the visibleEngines
*/
public Set<String> getVisibleEngines()
{
return new HashSet<String>(visibleEngines);
}
public void setWorkflowEngineConfigurations(List<Properties> props)
{
for (Properties prop : props)
{
String engineId = prop.getProperty(ENGINE);
String isEnabled = (String) prop.get(ENABLED);
if(isEnabled!=null)
{
setEngineEnabled(engineId, Boolean.valueOf(isEnabled));
}
String isVisible = (String) prop.get(VISIBLE);
if(isVisible!=null)
{
setEngineVisibility(engineId, Boolean.valueOf(isVisible));
}
}
}
}
package org.alfresco.repo.workflow;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.alfresco.service.cmr.workflow.WorkflowAdminService;
/**
* Default implementation of the workflow admin service.
*
* @author Gavin Cornwell
* @author Nick Smith
* @since 4.0
*/
public class WorkflowAdminServiceImpl implements WorkflowAdminService
{
public static final String NAME = "workflowAdminService";
public static final String ENGINE = "engineId";
public static final String ENABLED = "enabled";
public static final String VISIBLE = "visible";
private Set<String> enabledEngines = new HashSet<String>();
private Set<String> visibleEngines = new HashSet<String>();
/**
* {@inheritDoc}
*/
public boolean isEngineEnabled(String engineId)
{
return enabledEngines.contains(engineId);
}
/**
* {@inheritDoc}
*/
public void setEngineEnabled(String engineId, boolean isEnabled)
{
if(isEnabled)
{
enabledEngines.add(engineId);
}
else
{
enabledEngines.remove(engineId);
}
}
/**
* {@inheritDoc}
*/
public boolean isEngineVisible(String engineId)
{
return isEngineEnabled(engineId) && visibleEngines.contains(engineId);
}
/**
* {@inheritDoc}
*/
public void setEngineVisibility(String engineId, boolean isVisible)
{
if(isVisible)
{
visibleEngines.add(engineId);
}
else
{
visibleEngines.remove(engineId);
}
}
/**
* Setter for Spring
* @param engines All engine Ids to enable.
*/
public void setEnabledEngines(Collection<String> engines)
{
if(false == enabledEngines.isEmpty())
{
enabledEngines.clear();
}
enabledEngines.addAll(engines);
}
/**
* @return the enabledEngines
*/
public Set<String> getEnabledEngines()
{
return new HashSet<String>(enabledEngines);
}
/**
* Setter for Spring.
* @param engines All engineIds to set visible.
*/
public void setVisibleEngines(Collection<String> engines)
{
if(false == visibleEngines.isEmpty())
{
visibleEngines.clear();
}
visibleEngines.addAll(engines);
}
/**
* @return the visibleEngines
*/
public Set<String> getVisibleEngines()
{
return new HashSet<String>(visibleEngines);
}
public void setWorkflowEngineConfigurations(List<Properties> props)
{
for (Properties prop : props)
{
String engineId = prop.getProperty(ENGINE);
String isEnabled = (String) prop.get(ENABLED);
if(isEnabled!=null)
{
setEngineEnabled(engineId, Boolean.valueOf(isEnabled));
}
String isVisible = (String) prop.get(VISIBLE);
if(isVisible!=null)
{
setEngineVisibility(engineId, Boolean.valueOf(isVisible));
}
}
}
}

View File

@@ -1,322 +1,322 @@
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.Auditable;
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.WorkflowInstanceQuery;
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.WorkflowTimer;
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);
/**
* Deploy a Workflow Definition
*
* @param workflowDefinition the content object containing the definition
* @param mimetype (optional) the mime type of the workflow definition
* @param name (optional) a name to represent the deployment
* @return workflow deployment descriptor
* @since 4.0
*/
public WorkflowDeployment deployDefinition(InputStream workflowDefinition, String mimetype, String name);
/**
* 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 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
*
* @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$wf:review
* @return the deployed workflow definition
*/
public WorkflowDefinition getDefinitionByName(String workflowName);
/**
* Gets all (including previous) Workflow Definitions for the given unique name
*
* @param workflowName workflow name e.g. jbpm$wf: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
*
* @param workflowDefinitionId the workflow definition id
* @return graphical image of workflow definition
*/
@Auditable(parameters = {"workflowDefinitionId"})
public byte[] getDefinitionImage(String workflowDefinitionId);
/**
* Gets the Task Definitions for the given Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return the deployed task definitions (or null if not found)
*/
@Auditable(parameters = {"workflowDefinitionId"})
public List<WorkflowTaskDefinition> getTaskDefinitions(final String workflowDefinitionId);
//
// 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" active workflow instances of the specified Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return the list of "in-flight" workflow instances
*/
public List<WorkflowInstance> getActiveWorkflows(String workflowDefinitionId);
/**
* Gets all "in-flight" completed workflow instances of the specified Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return the list of "in-flight" workflow instances
*/
public List<WorkflowInstance> getCompletedWorkflows(String workflowDefinitionId);
/**
* Gets all "in-flight" workflow instances (both active and completed) of the specified Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return the list of "in-flight" workflow instances
*/
public List<WorkflowInstance> getWorkflows(String workflowDefinitionId);
/**
* Gets all "in-flight" workflow instances according to the specified workflowInstanceQuery parameter
*
* @param workflowInstanceQuery WorkflowInstanceQuery
* @return the list of "in-flight" workflow instances
*/
public List<WorkflowInstance> getWorkflows(WorkflowInstanceQuery workflowInstanceQuery);
/**
* Gets maxItems "in-flight" workflow instances according to the specified workflowInstanceQuery parameter
*
* @param workflowInstanceQuery WorkflowInstanceQuery
* @param maxItems int
* @param skipCount int
* @return maxItems workflow instances
*/
public List<WorkflowInstance> getWorkflows(WorkflowInstanceQuery workflowInstanceQuery, int maxItems, int skipCount);
/**
* Get count of workflow instances
*
* @param workflowInstanceQuery WorkflowInstanceQuery
* @return count of workflow instances
*/
public long countWorkflows(WorkflowInstanceQuery workflowInstanceQuery);
/**
* Gets all "in-flight" active workflow instances.
*
* @return the list of "in-flight" workflow instances
* @since 4.0
*/
public List<WorkflowInstance> getActiveWorkflows();
/**
* Gets all completed workflow instances.
*
* @return the list of "in-flight" workflow instances
* @since 4.0
*/
public List<WorkflowInstance> getCompletedWorkflows();
/**
* Gets all workflow instances (both active and completed).
*
* @return the list of "in-flight" workflow instances
* @since 4.0
*/
public List<WorkflowInstance> getWorkflows();
/**
* Gets a specific workflow instances
*
* @param workflowId the id of the workflow to retrieve
* @return the workflow instance
*/
public WorkflowInstance getWorkflowById(String workflowId);
/**
* Gets all Paths for the specified Workflow instance
*
* @param workflowId workflow instance id
* @return the list of workflow paths
*/
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-flight" Workflow instance
*
* @param workflowId the workflow instance to cancel
* @return an updated representation of the workflow instance
*/
public WorkflowInstance cancelWorkflow(String workflowId);
/**
* Cancel a batch of "in-flight" Workflow instances
*
* @param workflowIds List of the workflow instances to cancel
* @return List of updated representations of the workflow instances
*/
public List<WorkflowInstance> cancelWorkflows(List<String> workflowIds);
/**
* Delete an "in-flight" Workflow instance
*
* @param workflowId the workflow instance to cancel
* @return an updated representation of the workflow instance
*/
public WorkflowInstance deleteWorkflow(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 transitionId the transition id to follow (or null, for the default transition)
* @return the updated workflow path
*/
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
*
* @param pathId the path id
* @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);
/**
* Determines if a graphical view of the workflow instance exists
*
* @param workflowInstanceId the workflow instance id
* @return true if there is a workflow instance diagram available
* @since 4.0
*/
public boolean hasWorkflowImage(String workflowInstanceId);
/**
* Gets a graphical view of the workflow instance
*
* @param workflowInstanceId the workflow instance id
* @return image view of the workflow instance as an InputStream or null if a diagram is not available
* @since 4.0
*/
public InputStream getWorkflowImage(String workflowInstanceId);
}
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.Auditable;
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.WorkflowInstanceQuery;
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.WorkflowTimer;
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);
/**
* Deploy a Workflow Definition
*
* @param workflowDefinition the content object containing the definition
* @param mimetype (optional) the mime type of the workflow definition
* @param name (optional) a name to represent the deployment
* @return workflow deployment descriptor
* @since 4.0
*/
public WorkflowDeployment deployDefinition(InputStream workflowDefinition, String mimetype, String name);
/**
* 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 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
*
* @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$wf:review
* @return the deployed workflow definition
*/
public WorkflowDefinition getDefinitionByName(String workflowName);
/**
* Gets all (including previous) Workflow Definitions for the given unique name
*
* @param workflowName workflow name e.g. jbpm$wf: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
*
* @param workflowDefinitionId the workflow definition id
* @return graphical image of workflow definition
*/
@Auditable(parameters = {"workflowDefinitionId"})
public byte[] getDefinitionImage(String workflowDefinitionId);
/**
* Gets the Task Definitions for the given Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return the deployed task definitions (or null if not found)
*/
@Auditable(parameters = {"workflowDefinitionId"})
public List<WorkflowTaskDefinition> getTaskDefinitions(final String workflowDefinitionId);
//
// 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" active workflow instances of the specified Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return the list of "in-flight" workflow instances
*/
public List<WorkflowInstance> getActiveWorkflows(String workflowDefinitionId);
/**
* Gets all "in-flight" completed workflow instances of the specified Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return the list of "in-flight" workflow instances
*/
public List<WorkflowInstance> getCompletedWorkflows(String workflowDefinitionId);
/**
* Gets all "in-flight" workflow instances (both active and completed) of the specified Workflow Definition
*
* @param workflowDefinitionId the workflow definition id
* @return the list of "in-flight" workflow instances
*/
public List<WorkflowInstance> getWorkflows(String workflowDefinitionId);
/**
* Gets all "in-flight" workflow instances according to the specified workflowInstanceQuery parameter
*
* @param workflowInstanceQuery WorkflowInstanceQuery
* @return the list of "in-flight" workflow instances
*/
public List<WorkflowInstance> getWorkflows(WorkflowInstanceQuery workflowInstanceQuery);
/**
* Gets maxItems "in-flight" workflow instances according to the specified workflowInstanceQuery parameter
*
* @param workflowInstanceQuery WorkflowInstanceQuery
* @param maxItems int
* @param skipCount int
* @return maxItems workflow instances
*/
public List<WorkflowInstance> getWorkflows(WorkflowInstanceQuery workflowInstanceQuery, int maxItems, int skipCount);
/**
* Get count of workflow instances
*
* @param workflowInstanceQuery WorkflowInstanceQuery
* @return count of workflow instances
*/
public long countWorkflows(WorkflowInstanceQuery workflowInstanceQuery);
/**
* Gets all "in-flight" active workflow instances.
*
* @return the list of "in-flight" workflow instances
* @since 4.0
*/
public List<WorkflowInstance> getActiveWorkflows();
/**
* Gets all completed workflow instances.
*
* @return the list of "in-flight" workflow instances
* @since 4.0
*/
public List<WorkflowInstance> getCompletedWorkflows();
/**
* Gets all workflow instances (both active and completed).
*
* @return the list of "in-flight" workflow instances
* @since 4.0
*/
public List<WorkflowInstance> getWorkflows();
/**
* Gets a specific workflow instances
*
* @param workflowId the id of the workflow to retrieve
* @return the workflow instance
*/
public WorkflowInstance getWorkflowById(String workflowId);
/**
* Gets all Paths for the specified Workflow instance
*
* @param workflowId workflow instance id
* @return the list of workflow paths
*/
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-flight" Workflow instance
*
* @param workflowId the workflow instance to cancel
* @return an updated representation of the workflow instance
*/
public WorkflowInstance cancelWorkflow(String workflowId);
/**
* Cancel a batch of "in-flight" Workflow instances
*
* @param workflowIds List of the workflow instances to cancel
* @return List of updated representations of the workflow instances
*/
public List<WorkflowInstance> cancelWorkflows(List<String> workflowIds);
/**
* Delete an "in-flight" Workflow instance
*
* @param workflowId the workflow instance to cancel
* @return an updated representation of the workflow instance
*/
public WorkflowInstance deleteWorkflow(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 transitionId the transition id to follow (or null, for the default transition)
* @return the updated workflow path
*/
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
*
* @param pathId the path id
* @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);
/**
* Determines if a graphical view of the workflow instance exists
*
* @param workflowInstanceId the workflow instance id
* @return true if there is a workflow instance diagram available
* @since 4.0
*/
public boolean hasWorkflowImage(String workflowInstanceId);
/**
* Gets a graphical view of the workflow instance
*
* @param workflowInstanceId the workflow instance id
* @return image view of the workflow instance as an InputStream or null if a diagram is not available
* @since 4.0
*/
public InputStream getWorkflowImage(String workflowInstanceId);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,82 +1,82 @@
package org.alfresco.repo.workflow;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
/**
* Workflow Model Constants
*/
@AlfrescoPublicApi
public interface WorkflowModel
{
//
// Base Business Process Management Definitions
//
// package folder constants
static final QName TYPE_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "package");
static final QName ASSOC_PACKAGE_CONTAINS= QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageContains");
// 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 PROP_COMMENT = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "comment");
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_DESCRIPTION = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "description");
static final QName PROP_OUTCOME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "outcome");
static final QName PROP_PACKAGE_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageActionGroup");
static final QName PROP_PACKAGE_ITEM_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageItemActionGroup");
static final QName PROP_HIDDEN_TRANSITIONS = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "hiddenTransitions");
static final QName PROP_REASSIGNABLE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "reassignable");
static final QName ASSOC_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "package");
// Start task contstants
static final QName TYPE_START_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "startTask");
static final QName PROP_WORKFLOW_DESCRIPTION = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDescription");
static final QName PROP_WORKFLOW_PRIORITY = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowPriority");
static final QName PROP_WORKFLOW_DUE_DATE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDueDate");
static final QName ASSOC_ASSIGNEE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "assignee");
static final QName ASSOC_ASSIGNEES = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "assignees");
static final QName ASSOC_GROUP_ASSIGNEE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "groupAssignee");
static final QName ASSOC_GROUP_ASSIGNEES = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "groupAssignees");
// Activiti Task Constants
static final QName TYPE_ACTIVTI_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "activitiOutcomeTask");
static final QName PROP_OUTCOME_PROPERTY_NAME= QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "outcomePropertyName");
// Activiti Start Task Constants
static final QName TYPE_ACTIVTI_START_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "activitiStartTask");
// Activiti Start Task Constants
static final QName ASPECT_END_AUTOMATICALLY= QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "endAutomatically");
// workflow package
static final QName ASPECT_WORKFLOW_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowPackage");
static final QName PROP_IS_SYSTEM_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "isSystemPackage");
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 definition
static final QName TYPE_WORKFLOW_DEF = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDefinition");
static final QName PROP_WORKFLOW_DEF_ENGINE_ID = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "engineId");
static final QName PROP_WORKFLOW_DEF_NAME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "definitionName");
static final QName PROP_WORKFLOW_DEF_DEPLOYED = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "definitionDeployed");
static final QName PROP_SEND_EMAIL_NOTIFICATIONS = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "sendEMailNotifications");
package org.alfresco.repo.workflow;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
/**
* Workflow Model Constants
*/
@AlfrescoPublicApi
public interface WorkflowModel
{
//
// Base Business Process Management Definitions
//
// package folder constants
static final QName TYPE_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "package");
static final QName ASSOC_PACKAGE_CONTAINS= QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageContains");
// 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 PROP_COMMENT = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "comment");
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_DESCRIPTION = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "description");
static final QName PROP_OUTCOME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "outcome");
static final QName PROP_PACKAGE_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageActionGroup");
static final QName PROP_PACKAGE_ITEM_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageItemActionGroup");
static final QName PROP_HIDDEN_TRANSITIONS = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "hiddenTransitions");
static final QName PROP_REASSIGNABLE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "reassignable");
static final QName ASSOC_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "package");
// Start task contstants
static final QName TYPE_START_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "startTask");
static final QName PROP_WORKFLOW_DESCRIPTION = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDescription");
static final QName PROP_WORKFLOW_PRIORITY = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowPriority");
static final QName PROP_WORKFLOW_DUE_DATE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDueDate");
static final QName ASSOC_ASSIGNEE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "assignee");
static final QName ASSOC_ASSIGNEES = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "assignees");
static final QName ASSOC_GROUP_ASSIGNEE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "groupAssignee");
static final QName ASSOC_GROUP_ASSIGNEES = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "groupAssignees");
// Activiti Task Constants
static final QName TYPE_ACTIVTI_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "activitiOutcomeTask");
static final QName PROP_OUTCOME_PROPERTY_NAME= QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "outcomePropertyName");
// Activiti Start Task Constants
static final QName TYPE_ACTIVTI_START_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "activitiStartTask");
// Activiti Start Task Constants
static final QName ASPECT_END_AUTOMATICALLY= QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "endAutomatically");
// workflow package
static final QName ASPECT_WORKFLOW_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowPackage");
static final QName PROP_IS_SYSTEM_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "isSystemPackage");
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 definition
static final QName TYPE_WORKFLOW_DEF = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDefinition");
static final QName PROP_WORKFLOW_DEF_ENGINE_ID = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "engineId");
static final QName PROP_WORKFLOW_DEF_NAME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "definitionName");
static final QName PROP_WORKFLOW_DEF_DEPLOYED = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "definitionDeployed");
static final QName PROP_SEND_EMAIL_NOTIFICATIONS = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "sendEMailNotifications");
}

View File

@@ -1,60 +1,60 @@
package org.alfresco.repo.workflow;
import java.util.List;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowInstance;
/**
* 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);
/**
* Deletes a Workflow Package
*
* The workflow package aspect is removed, and if the container was previously created by the workflow
* service (i.e. not provided from elsewhere), it will be deleted.
*
* @param container NodeRef
*/
public void deletePackage(NodeRef container);
// TODO: Further support for finding packages via meta-data of WorkflowPackage aspect
/**
* Gets the Workflows that act upon the specified Repository content.
*
* @param packageItem the repository content item to get workflows for
* @return list of workflows which act upon the specified content
*/
public List<String> getWorkflowIdsForContent(NodeRef packageItem);
/**
* Initialises the workflow package node on the {@link WorkflowInstance},
* adding the appropriate aspect and setting the appropriate properties to
* mark it as a package for the given {@link WorkflowInstance}.
*
* @param instance
* the workflow instance to which the package belongs.
*
* @return <code>true</code> if the package node was modified.
*/
public boolean setWorkflowForPackage(WorkflowInstance instance);
}
package org.alfresco.repo.workflow;
import java.util.List;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowInstance;
/**
* 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);
/**
* Deletes a Workflow Package
*
* The workflow package aspect is removed, and if the container was previously created by the workflow
* service (i.e. not provided from elsewhere), it will be deleted.
*
* @param container NodeRef
*/
public void deletePackage(NodeRef container);
// TODO: Further support for finding packages via meta-data of WorkflowPackage aspect
/**
* Gets the Workflows that act upon the specified Repository content.
*
* @param packageItem the repository content item to get workflows for
* @return list of workflows which act upon the specified content
*/
public List<String> getWorkflowIdsForContent(NodeRef packageItem);
/**
* Initialises the workflow package node on the {@link WorkflowInstance},
* adding the appropriate aspect and setting the appropriate properties to
* mark it as a package for the given {@link WorkflowInstance}.
*
* @param instance
* the workflow instance to which the package belongs.
*
* @return <code>true</code> if the package node was modified.
*/
public boolean setWorkflowForPackage(WorkflowInstance instance);
}

View File

@@ -1,393 +1,393 @@
package org.alfresco.repo.workflow;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.i18n.MessageService;
import org.alfresco.repo.importer.ImporterBootstrap;
import org.alfresco.repo.node.SystemNodeUtils;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.workflow.traitextender.WorkflowPackageExtension;
import org.alfresco.repo.workflow.traitextender.WorkflowPackageTrait;
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.security.PermissionService;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.cmr.workflow.WorkflowInstance;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.traitextender.AJProxyTrait;
import org.alfresco.traitextender.Extend;
import org.alfresco.traitextender.ExtendedTrait;
import org.alfresco.traitextender.Extensible;
import org.alfresco.traitextender.Trait;
import org.alfresco.util.GUID;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* Alfresco implementation of Workflow Package where the package is stored
* within the Alfresco Repository.
*
* @author davidc
*/
public class WorkflowPackageImpl implements WorkflowPackageComponent,Extensible
{
private final static String PACKAGE_FOLDER = "packages";
private static final String ERR_PACKAGE_ALREADY_ASSOCIATED = "workflow.package.already.associated.error";
// service dependencies
private ImporterBootstrap bootstrap;
private SearchService searchService;
private NodeService nodeService;
private NamespaceService namespaceService;
private PermissionService permissionService;
private NodeRef systemWorkflowContainer = null;
private TenantService tenantService;
private MessageService messageService;
private BehaviourFilter policyBehaviourFilter;
private final ExtendedTrait<WorkflowPackageTrait> workflowPackageTrait;
public WorkflowPackageImpl()
{
workflowPackageTrait=new ExtendedTrait<WorkflowPackageTrait>(AJProxyTrait.create(this, WorkflowPackageTrait.class));
}
/**
* @param bootstrap the importer bootstrap for the store to place workflow
* items into
*/
public void setImporterBootstrap(ImporterBootstrap bootstrap)
{
this.bootstrap = bootstrap;
}
/**
* @param searchService search service
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* @param namespaceService namespace service
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param tenantService tenant service
*/
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
/**
* @param messageService the messageService to set
*/
public void setMessageService(MessageService messageService)
{
this.messageService = messageService;
}
/**
* @param policyBehaviourFilter the behaviourFilter to set
*/
public void setPolicyBehaviourFilter(BehaviourFilter policyBehaviourFilter) {
this.policyBehaviourFilter = policyBehaviourFilter;
}
/**
* {@inheritDoc}
*/
@Extend(traitAPI=WorkflowPackageTrait.class,extensionAPI=WorkflowPackageExtension.class)
public NodeRef createPackage(NodeRef container)
{
// create a container, if one is not specified
boolean isSystemPackage = false;
if (container == null)
{
container = makePackageContainer();
isSystemPackage = true;
}
// attach workflow package
if (nodeService.hasAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE))
{
String msg = "Container '" + container + "' is already a workflow package.";
throw new WorkflowException(msg);
}
nodeService.addAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE, null);
nodeService.setProperty(container, WorkflowModel.PROP_IS_SYSTEM_PACKAGE, isSystemPackage);
// return container
return container;
}
private NodeRef makePackageContainer()
{
NodeRef packages = findOrCreatePackagesFolder();
String packageId = "pkg_" + GUID.generate();
QName packageName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, packageId);
try {
policyBehaviourFilter.disableBehaviour(packages, ContentModel.ASPECT_AUDITABLE);
ChildAssociationRef packageAssoc = nodeService.createNode(packages, ContentModel.ASSOC_CONTAINS, packageName,
WorkflowModel.TYPE_PACKAGE);
NodeRef packageContainer = packageAssoc.getChildRef();
// TODO: For now, grant full access to everyone
permissionService.setPermission(packageContainer, PermissionService.ALL_AUTHORITIES,
PermissionService.ALL_PERMISSIONS, true);
return packageContainer;
}
finally
{
policyBehaviourFilter.enableBehaviour(packages, ContentModel.ASPECT_AUDITABLE);
}
}
/**
* Finds the system folder in which all packages are stored. If this folder
* has not been created yet then this method creates a new packages folder.
*
* @return The system folder containing all workflow packages.
*/
private NodeRef findOrCreatePackagesFolder()
{
// create simple folder in workflow system folder
NodeRef system = getSystemWorkflowContainer();
// TODO: Consider structuring this folder, if number of children becomes
// an issue
List<NodeRef> packageFolders = searchService.selectNodes(system, "./" + NamespaceService.CONTENT_MODEL_PREFIX
+ ":" + PACKAGE_FOLDER, null, namespaceService, false);
if (packageFolders.size() > 0)
{
return packageFolders.get(0); // Return folder if exists.
}
else
// Create new package folder
{
QName packageFolderName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, PACKAGE_FOLDER);
ChildAssociationRef packageFolderAssoc = nodeService.createNode(system, ContentModel.ASSOC_CHILDREN,
packageFolderName, ContentModel.TYPE_SYSTEM_FOLDER);
return packageFolderAssoc.getChildRef();
}
}
/**
* {@inheritDoc}
*/
@Extend(traitAPI=WorkflowPackageTrait.class,extensionAPI=WorkflowPackageExtension.class)
public void deletePackage(NodeRef container)
{
if (container != null && nodeService.exists(container)
&& nodeService.hasAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE))
{
Boolean isSystemPackage = (Boolean) nodeService
.getProperty(container, WorkflowModel.PROP_IS_SYSTEM_PACKAGE);
if (isSystemPackage != null && isSystemPackage.booleanValue())
{
nodeService.deleteNode(container);
}
else
{
nodeService.removeAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE);
}
}
}
/**
* {@inheritDoc}
*/
@Extend(traitAPI=WorkflowPackageTrait.class,extensionAPI=WorkflowPackageExtension.class)
public List<String> getWorkflowIdsForContent(NodeRef packageItem)
{
ParameterCheck.mandatory("packageItem", packageItem);
List<String> workflowIds = new ArrayList<String>();
if (nodeService.exists(packageItem))
{
List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(packageItem);
for (ChildAssociationRef parentAssoc : parentAssocs)
{
NodeRef parentRef = parentAssoc.getParentRef();
if (nodeService.hasAspect(parentRef, WorkflowModel.ASPECT_WORKFLOW_PACKAGE)
&& !nodeService.hasAspect(parentRef, ContentModel.ASPECT_ARCHIVED))
{
String workflowInstance = (String) nodeService.getProperty(parentRef,
WorkflowModel.PROP_WORKFLOW_INSTANCE_ID);
if (workflowInstance != null && workflowInstance.length() > 0)
{
workflowIds.add(workflowInstance);
}
}
}
}
return workflowIds;
}
/**
* Gets the system workflow container for storing workflow related items
*
* TODO Replace this with calls to {@link SystemNodeUtils}
*
* @return the system workflow container
*/
private NodeRef getSystemWorkflowContainer()
{
if (tenantService.isEnabled())
{
NodeRef systemContainer = findSystemContainer();
NodeRef tenantSystemWorkflowContainer = findSystemWorkflowContainer(systemContainer);
if (tenantSystemWorkflowContainer == null) { throw new WorkflowException(
"Unable to find system workflow folder - does not exist."); }
return tenantSystemWorkflowContainer;
}
else
{
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);
NodeRef result = null;
if (nodeRefs != null && nodeRefs.size() > 0)
{
result = nodeRefs.get(0);
}
if (tenantService.isEnabled() == false)
{
if(result == null)
{
result = systemWorkflowContainer;
}
else
{
systemWorkflowContainer = result;
}
}
return result;
}
/**
* 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 systemWfContainer = findSystemWorkflowContainer(systemContainer);
if (systemWfContainer == 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_CONTAINER);
systemWfContainer = childRef.getChildRef();
}
return systemWfContainer;
}
/**
* {@inheritDoc}
*/
@Extend(traitAPI=WorkflowPackageTrait.class,extensionAPI=WorkflowPackageExtension.class)
public boolean setWorkflowForPackage(WorkflowInstance instance)
{
NodeRef packageNode = instance.getWorkflowPackage();
if(packageNode==null)
return false;
Serializable pckgInstanceId = nodeService.getProperty(packageNode, WorkflowModel.PROP_WORKFLOW_INSTANCE_ID);
if(pckgInstanceId != null)
{
if(pckgInstanceId.equals(instance.getId()))
{
return false;
}
String msg = messageService.getMessage(ERR_PACKAGE_ALREADY_ASSOCIATED, packageNode,
instance.getId(), pckgInstanceId);
throw new WorkflowException(msg);
}
if (nodeService.hasAspect(packageNode, WorkflowModel.ASPECT_WORKFLOW_PACKAGE)==false)
{
createPackage(packageNode);
}
String definitionId = instance.getDefinition().getId();
String definitionName = instance.getDefinition().getName();
String instanceId = instance.getId();
nodeService.setProperty(packageNode, WorkflowModel.PROP_WORKFLOW_DEFINITION_ID, definitionId);
nodeService.setProperty(packageNode, WorkflowModel.PROP_WORKFLOW_DEFINITION_NAME, definitionName);
nodeService.setProperty(packageNode, WorkflowModel.PROP_WORKFLOW_INSTANCE_ID, instanceId);
return true;
}
@Override
public <T extends Trait> ExtendedTrait<T> getTrait(Class<? extends T> traitAPI)
{
return (ExtendedTrait<T>) workflowPackageTrait;
}
}
package org.alfresco.repo.workflow;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.i18n.MessageService;
import org.alfresco.repo.importer.ImporterBootstrap;
import org.alfresco.repo.node.SystemNodeUtils;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.workflow.traitextender.WorkflowPackageExtension;
import org.alfresco.repo.workflow.traitextender.WorkflowPackageTrait;
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.security.PermissionService;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.cmr.workflow.WorkflowInstance;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.traitextender.AJProxyTrait;
import org.alfresco.traitextender.Extend;
import org.alfresco.traitextender.ExtendedTrait;
import org.alfresco.traitextender.Extensible;
import org.alfresco.traitextender.Trait;
import org.alfresco.util.GUID;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* Alfresco implementation of Workflow Package where the package is stored
* within the Alfresco Repository.
*
* @author davidc
*/
public class WorkflowPackageImpl implements WorkflowPackageComponent,Extensible
{
private final static String PACKAGE_FOLDER = "packages";
private static final String ERR_PACKAGE_ALREADY_ASSOCIATED = "workflow.package.already.associated.error";
// service dependencies
private ImporterBootstrap bootstrap;
private SearchService searchService;
private NodeService nodeService;
private NamespaceService namespaceService;
private PermissionService permissionService;
private NodeRef systemWorkflowContainer = null;
private TenantService tenantService;
private MessageService messageService;
private BehaviourFilter policyBehaviourFilter;
private final ExtendedTrait<WorkflowPackageTrait> workflowPackageTrait;
public WorkflowPackageImpl()
{
workflowPackageTrait=new ExtendedTrait<WorkflowPackageTrait>(AJProxyTrait.create(this, WorkflowPackageTrait.class));
}
/**
* @param bootstrap the importer bootstrap for the store to place workflow
* items into
*/
public void setImporterBootstrap(ImporterBootstrap bootstrap)
{
this.bootstrap = bootstrap;
}
/**
* @param searchService search service
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* @param namespaceService namespace service
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param tenantService tenant service
*/
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
/**
* @param messageService the messageService to set
*/
public void setMessageService(MessageService messageService)
{
this.messageService = messageService;
}
/**
* @param policyBehaviourFilter the behaviourFilter to set
*/
public void setPolicyBehaviourFilter(BehaviourFilter policyBehaviourFilter) {
this.policyBehaviourFilter = policyBehaviourFilter;
}
/**
* {@inheritDoc}
*/
@Extend(traitAPI=WorkflowPackageTrait.class,extensionAPI=WorkflowPackageExtension.class)
public NodeRef createPackage(NodeRef container)
{
// create a container, if one is not specified
boolean isSystemPackage = false;
if (container == null)
{
container = makePackageContainer();
isSystemPackage = true;
}
// attach workflow package
if (nodeService.hasAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE))
{
String msg = "Container '" + container + "' is already a workflow package.";
throw new WorkflowException(msg);
}
nodeService.addAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE, null);
nodeService.setProperty(container, WorkflowModel.PROP_IS_SYSTEM_PACKAGE, isSystemPackage);
// return container
return container;
}
private NodeRef makePackageContainer()
{
NodeRef packages = findOrCreatePackagesFolder();
String packageId = "pkg_" + GUID.generate();
QName packageName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, packageId);
try {
policyBehaviourFilter.disableBehaviour(packages, ContentModel.ASPECT_AUDITABLE);
ChildAssociationRef packageAssoc = nodeService.createNode(packages, ContentModel.ASSOC_CONTAINS, packageName,
WorkflowModel.TYPE_PACKAGE);
NodeRef packageContainer = packageAssoc.getChildRef();
// TODO: For now, grant full access to everyone
permissionService.setPermission(packageContainer, PermissionService.ALL_AUTHORITIES,
PermissionService.ALL_PERMISSIONS, true);
return packageContainer;
}
finally
{
policyBehaviourFilter.enableBehaviour(packages, ContentModel.ASPECT_AUDITABLE);
}
}
/**
* Finds the system folder in which all packages are stored. If this folder
* has not been created yet then this method creates a new packages folder.
*
* @return The system folder containing all workflow packages.
*/
private NodeRef findOrCreatePackagesFolder()
{
// create simple folder in workflow system folder
NodeRef system = getSystemWorkflowContainer();
// TODO: Consider structuring this folder, if number of children becomes
// an issue
List<NodeRef> packageFolders = searchService.selectNodes(system, "./" + NamespaceService.CONTENT_MODEL_PREFIX
+ ":" + PACKAGE_FOLDER, null, namespaceService, false);
if (packageFolders.size() > 0)
{
return packageFolders.get(0); // Return folder if exists.
}
else
// Create new package folder
{
QName packageFolderName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, PACKAGE_FOLDER);
ChildAssociationRef packageFolderAssoc = nodeService.createNode(system, ContentModel.ASSOC_CHILDREN,
packageFolderName, ContentModel.TYPE_SYSTEM_FOLDER);
return packageFolderAssoc.getChildRef();
}
}
/**
* {@inheritDoc}
*/
@Extend(traitAPI=WorkflowPackageTrait.class,extensionAPI=WorkflowPackageExtension.class)
public void deletePackage(NodeRef container)
{
if (container != null && nodeService.exists(container)
&& nodeService.hasAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE))
{
Boolean isSystemPackage = (Boolean) nodeService
.getProperty(container, WorkflowModel.PROP_IS_SYSTEM_PACKAGE);
if (isSystemPackage != null && isSystemPackage.booleanValue())
{
nodeService.deleteNode(container);
}
else
{
nodeService.removeAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE);
}
}
}
/**
* {@inheritDoc}
*/
@Extend(traitAPI=WorkflowPackageTrait.class,extensionAPI=WorkflowPackageExtension.class)
public List<String> getWorkflowIdsForContent(NodeRef packageItem)
{
ParameterCheck.mandatory("packageItem", packageItem);
List<String> workflowIds = new ArrayList<String>();
if (nodeService.exists(packageItem))
{
List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(packageItem);
for (ChildAssociationRef parentAssoc : parentAssocs)
{
NodeRef parentRef = parentAssoc.getParentRef();
if (nodeService.hasAspect(parentRef, WorkflowModel.ASPECT_WORKFLOW_PACKAGE)
&& !nodeService.hasAspect(parentRef, ContentModel.ASPECT_ARCHIVED))
{
String workflowInstance = (String) nodeService.getProperty(parentRef,
WorkflowModel.PROP_WORKFLOW_INSTANCE_ID);
if (workflowInstance != null && workflowInstance.length() > 0)
{
workflowIds.add(workflowInstance);
}
}
}
}
return workflowIds;
}
/**
* Gets the system workflow container for storing workflow related items
*
* TODO Replace this with calls to {@link SystemNodeUtils}
*
* @return the system workflow container
*/
private NodeRef getSystemWorkflowContainer()
{
if (tenantService.isEnabled())
{
NodeRef systemContainer = findSystemContainer();
NodeRef tenantSystemWorkflowContainer = findSystemWorkflowContainer(systemContainer);
if (tenantSystemWorkflowContainer == null) { throw new WorkflowException(
"Unable to find system workflow folder - does not exist."); }
return tenantSystemWorkflowContainer;
}
else
{
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);
NodeRef result = null;
if (nodeRefs != null && nodeRefs.size() > 0)
{
result = nodeRefs.get(0);
}
if (tenantService.isEnabled() == false)
{
if(result == null)
{
result = systemWorkflowContainer;
}
else
{
systemWorkflowContainer = result;
}
}
return result;
}
/**
* 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 systemWfContainer = findSystemWorkflowContainer(systemContainer);
if (systemWfContainer == 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_CONTAINER);
systemWfContainer = childRef.getChildRef();
}
return systemWfContainer;
}
/**
* {@inheritDoc}
*/
@Extend(traitAPI=WorkflowPackageTrait.class,extensionAPI=WorkflowPackageExtension.class)
public boolean setWorkflowForPackage(WorkflowInstance instance)
{
NodeRef packageNode = instance.getWorkflowPackage();
if(packageNode==null)
return false;
Serializable pckgInstanceId = nodeService.getProperty(packageNode, WorkflowModel.PROP_WORKFLOW_INSTANCE_ID);
if(pckgInstanceId != null)
{
if(pckgInstanceId.equals(instance.getId()))
{
return false;
}
String msg = messageService.getMessage(ERR_PACKAGE_ALREADY_ASSOCIATED, packageNode,
instance.getId(), pckgInstanceId);
throw new WorkflowException(msg);
}
if (nodeService.hasAspect(packageNode, WorkflowModel.ASPECT_WORKFLOW_PACKAGE)==false)
{
createPackage(packageNode);
}
String definitionId = instance.getDefinition().getId();
String definitionName = instance.getDefinition().getName();
String instanceId = instance.getId();
nodeService.setProperty(packageNode, WorkflowModel.PROP_WORKFLOW_DEFINITION_ID, definitionId);
nodeService.setProperty(packageNode, WorkflowModel.PROP_WORKFLOW_DEFINITION_NAME, definitionName);
nodeService.setProperty(packageNode, WorkflowModel.PROP_WORKFLOW_INSTANCE_ID, instanceId);
return true;
}
@Override
public <T extends Trait> ExtendedTrait<T> getTrait(Class<? extends T> traitAPI)
{
return (ExtendedTrait<T>) workflowPackageTrait;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,245 +1,245 @@
package org.alfresco.repo.workflow.jbpm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.repo.security.authority.AuthorityDAO;
import org.alfresco.repo.workflow.WorkflowNotificationUtils;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.namespace.QName;
import org.dom4j.Element;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.taskmgmt.exe.Assignable;
import org.springframework.beans.factory.BeanFactory;
/**
* Assignment Handler for assigning Alfresco People and Groups to Tasks
* and Swimlanes
*
* @author davidc
*/
public class AlfrescoAssignment extends JBPMSpringAssignmentHandler
{
private static final long serialVersionUID = 1025667849552265719L;
private ServiceRegistry services;
private DictionaryService dictionaryService;
private AuthorityDAO authorityDAO;
private WorkflowNotificationUtils workflowNotificationUtils;
private Element actor;
private Element pooledactors;
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler#initialiseHandler(org.springframework.beans.factory.BeanFactory)
*/
@Override
protected void initialiseHandler(BeanFactory factory)
{
services = (ServiceRegistry)factory.getBean(ServiceRegistry.SERVICE_REGISTRY);
dictionaryService = services.getDictionaryService();
authorityDAO = (AuthorityDAO)factory.getBean("authorityDAO");
workflowNotificationUtils = (WorkflowNotificationUtils)factory.getBean("workflowNotification");
}
/* (non-Javadoc)
* @see org.jbpm.taskmgmt.def.AssignmentHandler#assign(org.jbpm.taskmgmt.exe.Assignable, org.jbpm.graph.exe.ExecutionContext)
*/
public void assign(Assignable assignable, ExecutionContext executionContext) throws Exception
{
if (actor == null && pooledactors == null)
{
throw new WorkflowException("no actor or pooled actors has been specified");
}
//
// extract actor
//
String assignedActor = null;
if (actor != null)
{
String actorValStr = actor.getTextTrim();
if (actorValStr != null && actorValStr.length() > 0)
{
if (actorValStr.startsWith("#{"))
{
String expression = actorValStr.substring(2, actorValStr.length() -1);
Object eval = AlfrescoJavaScript.executeScript(executionContext, services, expression, null, null);
if (eval == null)
{
throw new WorkflowException("actor expression '" + actorValStr + "' evaluates to null");
}
String theActor = null;
if (eval instanceof String)
{
theActor = (String)eval;
}
else if (eval instanceof JBPMNode)
{
theActor = mapAuthorityToName((JBPMNode)eval, false);
}
if (theActor == null)
{
throw new WorkflowException("actor expression must evaluate to a person");
}
assignedActor = theActor;
}
else
{
assignedActor = actorValStr;
}
}
}
//
// extract pooled actors
//
String[] assignedPooledActors = null;
if (pooledactors != null)
{
String pooledactorValStr = pooledactors.getTextTrim();
if (pooledactorValStr != null && pooledactorValStr.length() > 0)
{
if (pooledactorValStr.startsWith("#{"))
{
String expression = pooledactorValStr.substring(2, pooledactorValStr.length() -1);
Object eval = AlfrescoJavaScript.executeScript(executionContext, services, expression, null, null);
if (eval == null)
{
throw new WorkflowException("pooledactors expression '" + pooledactorValStr + "' evaluates to null");
}
if (eval instanceof ScriptNode[])
{
ScriptNode[] nodes = (ScriptNode[])eval;
assignedPooledActors = new String[nodes.length];
int i = 0;
for (ScriptNode node : nodes)
{
String theActor = mapAuthorityToName(node, true);
if (theActor == null)
{
throw new WorkflowException("pooledactors expression does not evaluate to a collection of authorities");
}
assignedPooledActors[i++] = theActor;
}
}
if (eval instanceof Collection)
{
List<String> actors = new ArrayList<String>();
Collection<?> nodes = (Collection<?>)eval;
for (Object node : nodes)
{
if (node instanceof ScriptNode)
{
String theActor = mapAuthorityToName((ScriptNode)node, true);
if (theActor == null)
{
throw new WorkflowException("pooledactors expression does not evaluate to a collection of authorities");
}
actors.add(theActor);
}
}
assignedPooledActors = new String[actors.size()];
actors.toArray(assignedPooledActors);
}
else if (eval instanceof ScriptNode)
{
ScriptNode node = (ScriptNode)eval;
String theActor = mapAuthorityToName(node, true);
if (theActor == null)
{
throw new WorkflowException("pooledactors expression does not evaluate to a collection of authorities");
}
assignedPooledActors = new String[] {theActor};
}
else if (eval instanceof String)
{
assignedPooledActors = new String[] {(String)eval};
}
else
{
throw new WorkflowException("pooledactors expression does not evaluate to a collection of authorities");
}
}
else
{
assignedPooledActors = new String[] {pooledactorValStr};
}
}
}
//Determine whether we need to send email notifications of not
Boolean sendEMailNotification = (Boolean)executionContext.getVariable(WorkflowNotificationUtils.PROP_SEND_EMAIL_NOTIFICATIONS);
//
// make the assignment
//
if (assignedActor != null)
{
assignable.setActorId(assignedActor);
if (Boolean.TRUE.equals(sendEMailNotification) == true)
{
// Send the notification
workflowNotificationUtils.sendWorkflowAssignedNotificationEMail(
JBPMEngine.ENGINE_ID + "$" + executionContext.getTaskInstance().getId(), null,
assignedActor,
false);
}
}
if (assignedPooledActors != null)
{
assignable.setPooledActors(assignedPooledActors);
if (Boolean.TRUE.equals(sendEMailNotification) == true)
{
// Send the notification
workflowNotificationUtils.sendWorkflowAssignedNotificationEMail(
JBPMEngine.ENGINE_ID + "$" + executionContext.getTaskInstance().getId(), null,
assignedPooledActors,
true);
}
}
}
/**
* Convert Alfresco authority to actor id
*
* @param authority ScriptNode
* @param allowGroup boolean
* @return actor id
*/
private String mapAuthorityToName(ScriptNode authority, boolean allowGroup)
{
String name = null;
QName type = authority.getQNameType();
if (dictionaryService.isSubClass(type, ContentModel.TYPE_PERSON))
{
name = (String)authority.getProperties().get(ContentModel.PROP_USERNAME);
}
else if (allowGroup && dictionaryService.isSubClass(type, ContentModel.TYPE_AUTHORITY_CONTAINER))
{
name = authorityDAO.getAuthorityName(authority.getNodeRef());
}
else if (type.equals(ContentModel.TYPE_AUTHORITY))
{
name = authorityDAO.getAuthorityName(authority.getNodeRef());
}
return name;
}
}
package org.alfresco.repo.workflow.jbpm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.repo.security.authority.AuthorityDAO;
import org.alfresco.repo.workflow.WorkflowNotificationUtils;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.namespace.QName;
import org.dom4j.Element;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.taskmgmt.exe.Assignable;
import org.springframework.beans.factory.BeanFactory;
/**
* Assignment Handler for assigning Alfresco People and Groups to Tasks
* and Swimlanes
*
* @author davidc
*/
public class AlfrescoAssignment extends JBPMSpringAssignmentHandler
{
private static final long serialVersionUID = 1025667849552265719L;
private ServiceRegistry services;
private DictionaryService dictionaryService;
private AuthorityDAO authorityDAO;
private WorkflowNotificationUtils workflowNotificationUtils;
private Element actor;
private Element pooledactors;
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler#initialiseHandler(org.springframework.beans.factory.BeanFactory)
*/
@Override
protected void initialiseHandler(BeanFactory factory)
{
services = (ServiceRegistry)factory.getBean(ServiceRegistry.SERVICE_REGISTRY);
dictionaryService = services.getDictionaryService();
authorityDAO = (AuthorityDAO)factory.getBean("authorityDAO");
workflowNotificationUtils = (WorkflowNotificationUtils)factory.getBean("workflowNotification");
}
/* (non-Javadoc)
* @see org.jbpm.taskmgmt.def.AssignmentHandler#assign(org.jbpm.taskmgmt.exe.Assignable, org.jbpm.graph.exe.ExecutionContext)
*/
public void assign(Assignable assignable, ExecutionContext executionContext) throws Exception
{
if (actor == null && pooledactors == null)
{
throw new WorkflowException("no actor or pooled actors has been specified");
}
//
// extract actor
//
String assignedActor = null;
if (actor != null)
{
String actorValStr = actor.getTextTrim();
if (actorValStr != null && actorValStr.length() > 0)
{
if (actorValStr.startsWith("#{"))
{
String expression = actorValStr.substring(2, actorValStr.length() -1);
Object eval = AlfrescoJavaScript.executeScript(executionContext, services, expression, null, null);
if (eval == null)
{
throw new WorkflowException("actor expression '" + actorValStr + "' evaluates to null");
}
String theActor = null;
if (eval instanceof String)
{
theActor = (String)eval;
}
else if (eval instanceof JBPMNode)
{
theActor = mapAuthorityToName((JBPMNode)eval, false);
}
if (theActor == null)
{
throw new WorkflowException("actor expression must evaluate to a person");
}
assignedActor = theActor;
}
else
{
assignedActor = actorValStr;
}
}
}
//
// extract pooled actors
//
String[] assignedPooledActors = null;
if (pooledactors != null)
{
String pooledactorValStr = pooledactors.getTextTrim();
if (pooledactorValStr != null && pooledactorValStr.length() > 0)
{
if (pooledactorValStr.startsWith("#{"))
{
String expression = pooledactorValStr.substring(2, pooledactorValStr.length() -1);
Object eval = AlfrescoJavaScript.executeScript(executionContext, services, expression, null, null);
if (eval == null)
{
throw new WorkflowException("pooledactors expression '" + pooledactorValStr + "' evaluates to null");
}
if (eval instanceof ScriptNode[])
{
ScriptNode[] nodes = (ScriptNode[])eval;
assignedPooledActors = new String[nodes.length];
int i = 0;
for (ScriptNode node : nodes)
{
String theActor = mapAuthorityToName(node, true);
if (theActor == null)
{
throw new WorkflowException("pooledactors expression does not evaluate to a collection of authorities");
}
assignedPooledActors[i++] = theActor;
}
}
if (eval instanceof Collection)
{
List<String> actors = new ArrayList<String>();
Collection<?> nodes = (Collection<?>)eval;
for (Object node : nodes)
{
if (node instanceof ScriptNode)
{
String theActor = mapAuthorityToName((ScriptNode)node, true);
if (theActor == null)
{
throw new WorkflowException("pooledactors expression does not evaluate to a collection of authorities");
}
actors.add(theActor);
}
}
assignedPooledActors = new String[actors.size()];
actors.toArray(assignedPooledActors);
}
else if (eval instanceof ScriptNode)
{
ScriptNode node = (ScriptNode)eval;
String theActor = mapAuthorityToName(node, true);
if (theActor == null)
{
throw new WorkflowException("pooledactors expression does not evaluate to a collection of authorities");
}
assignedPooledActors = new String[] {theActor};
}
else if (eval instanceof String)
{
assignedPooledActors = new String[] {(String)eval};
}
else
{
throw new WorkflowException("pooledactors expression does not evaluate to a collection of authorities");
}
}
else
{
assignedPooledActors = new String[] {pooledactorValStr};
}
}
}
//Determine whether we need to send email notifications of not
Boolean sendEMailNotification = (Boolean)executionContext.getVariable(WorkflowNotificationUtils.PROP_SEND_EMAIL_NOTIFICATIONS);
//
// make the assignment
//
if (assignedActor != null)
{
assignable.setActorId(assignedActor);
if (Boolean.TRUE.equals(sendEMailNotification) == true)
{
// Send the notification
workflowNotificationUtils.sendWorkflowAssignedNotificationEMail(
JBPMEngine.ENGINE_ID + "$" + executionContext.getTaskInstance().getId(), null,
assignedActor,
false);
}
}
if (assignedPooledActors != null)
{
assignable.setPooledActors(assignedPooledActors);
if (Boolean.TRUE.equals(sendEMailNotification) == true)
{
// Send the notification
workflowNotificationUtils.sendWorkflowAssignedNotificationEMail(
JBPMEngine.ENGINE_ID + "$" + executionContext.getTaskInstance().getId(), null,
assignedPooledActors,
true);
}
}
}
/**
* Convert Alfresco authority to actor id
*
* @param authority ScriptNode
* @param allowGroup boolean
* @return actor id
*/
private String mapAuthorityToName(ScriptNode authority, boolean allowGroup)
{
String name = null;
QName type = authority.getQNameType();
if (dictionaryService.isSubClass(type, ContentModel.TYPE_PERSON))
{
name = (String)authority.getProperties().get(ContentModel.PROP_USERNAME);
}
else if (allowGroup && dictionaryService.isSubClass(type, ContentModel.TYPE_AUTHORITY_CONTAINER))
{
name = authorityDAO.getAuthorityName(authority.getNodeRef());
}
else if (type.equals(ContentModel.TYPE_AUTHORITY))
{
name = authorityDAO.getAuthorityName(authority.getNodeRef());
}
return name;
}
}

View File

@@ -1,88 +1,88 @@
package org.alfresco.repo.workflow.jbpm;
import java.util.Calendar;
import java.util.Date;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.jbpm.calendar.BusinessCalendar;
import org.jbpm.calendar.Duration;
import org.jbpm.graph.def.GraphElement;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.job.Timer;
import org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator;
import org.jbpm.scheduler.def.CreateTimerAction;
/**
* Extended Create Timer action for supporting Alfresco implemented timers.
*
* Alfresco timer supports ability to provide due date expression that can
* evaluate to a date.
*
* @author davidc
*/
public class AlfrescoCreateTimerAction extends CreateTimerAction
{
private static final long serialVersionUID = -7427571820130058416L;
protected static BusinessCalendar businessCalendar = new BusinessCalendar();
/* (non-Javadoc)
* @see org.jbpm.scheduler.def.CreateTimerAction#createTimer(org.jbpm.graph.exe.ExecutionContext)
*/
@Override
protected Timer createTimer(ExecutionContext executionContext)
{
Date dueDate = null;
String dueDateExpression = getDueDate();
if (dueDateExpression.startsWith("#{"))
{
Object result = JbpmExpressionEvaluator.evaluate(dueDateExpression, executionContext);
if (result instanceof Date)
{
dueDate = (Date)result;
}
else if(result instanceof Calendar)
{
dueDate = ((Calendar)result).getTime();
}
else
{
throw new WorkflowException("duedate expression must evaluate to a date");
}
}
else
{
Duration duration = new Duration(getDueDate());
dueDate = businessCalendar.add(new Date(), duration);
}
Timer timer = new AlfrescoTimer(executionContext.getToken());
timer.setName(getTimerName());
timer.setRepeat(getRepeat());
timer.setDueDate(dueDate);
timer.setAction(getTimerAction());
timer.setTransitionName(getTransitionName());
timer.setGraphElement(executionContext.getEventSource());
timer.setTaskInstance(executionContext.getTaskInstance());
// if this action was executed for a graph element
if ((getEvent() != null) && (getEvent().getGraphElement() != null))
{
GraphElement graphElement = getEvent().getGraphElement();
try
{
executionContext.setTimer(timer);
// fire the create timer event on the same graph element
graphElement.fireEvent("timer-create", executionContext);
}
finally
{
executionContext.setTimer(null);
}
}
return timer;
}
}
package org.alfresco.repo.workflow.jbpm;
import java.util.Calendar;
import java.util.Date;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.jbpm.calendar.BusinessCalendar;
import org.jbpm.calendar.Duration;
import org.jbpm.graph.def.GraphElement;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.job.Timer;
import org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator;
import org.jbpm.scheduler.def.CreateTimerAction;
/**
* Extended Create Timer action for supporting Alfresco implemented timers.
*
* Alfresco timer supports ability to provide due date expression that can
* evaluate to a date.
*
* @author davidc
*/
public class AlfrescoCreateTimerAction extends CreateTimerAction
{
private static final long serialVersionUID = -7427571820130058416L;
protected static BusinessCalendar businessCalendar = new BusinessCalendar();
/* (non-Javadoc)
* @see org.jbpm.scheduler.def.CreateTimerAction#createTimer(org.jbpm.graph.exe.ExecutionContext)
*/
@Override
protected Timer createTimer(ExecutionContext executionContext)
{
Date dueDate = null;
String dueDateExpression = getDueDate();
if (dueDateExpression.startsWith("#{"))
{
Object result = JbpmExpressionEvaluator.evaluate(dueDateExpression, executionContext);
if (result instanceof Date)
{
dueDate = (Date)result;
}
else if(result instanceof Calendar)
{
dueDate = ((Calendar)result).getTime();
}
else
{
throw new WorkflowException("duedate expression must evaluate to a date");
}
}
else
{
Duration duration = new Duration(getDueDate());
dueDate = businessCalendar.add(new Date(), duration);
}
Timer timer = new AlfrescoTimer(executionContext.getToken());
timer.setName(getTimerName());
timer.setRepeat(getRepeat());
timer.setDueDate(dueDate);
timer.setAction(getTimerAction());
timer.setTransitionName(getTransitionName());
timer.setGraphElement(executionContext.getEventSource());
timer.setTaskInstance(executionContext.getTaskInstance());
// if this action was executed for a graph element
if ((getEvent() != null) && (getEvent().getGraphElement() != null))
{
GraphElement graphElement = getEvent().getGraphElement();
try
{
executionContext.setTimer(timer);
// fire the create timer event on the same graph element
graphElement.fireEvent("timer-create", executionContext);
}
finally
{
executionContext.setTimer(null);
}
}
return timer;
}
}

View File

@@ -1,472 +1,472 @@
package org.alfresco.repo.workflow.jbpm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
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.ScriptService;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.dom4j.Element;
import org.jbpm.context.def.VariableAccess;
import org.jbpm.context.exe.ContextInstance;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;
import org.jbpm.jpdl.xml.JpdlXmlReader;
import org.jbpm.taskmgmt.def.Task;
import org.jbpm.taskmgmt.exe.TaskInstance;
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>
* <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 ServiceRegistry services;
private NodeRef companyHome;
private Element script;
private String runas;
/**
* {@inheritDoc}
*/
@Override
protected void initialiseHandler(BeanFactory factory)
{
this.services = (ServiceRegistry)factory.getBean(ServiceRegistry.SERVICE_REGISTRY);
Repository repositoryHelper = (Repository)factory.getBean("repositoryHelper");
this.companyHome = repositoryHelper.getCompanyHome();
}
/* (non-Javadoc)
* @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
*/
public void execute(final ExecutionContext executionContext) throws Exception
{
// validate script
if (script == null)
{
throw new WorkflowException("Script has not been provided");
}
boolean isTextOnly = isScriptOnlyText();
List<VariableAccess> variableAccesses = getVariableAccessors(isTextOnly);
String expression = getExpression(isTextOnly);
// execute
Object result = executeExpression(expression, executionContext, variableAccesses);
// 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);
}
}
private Object executeExpression(String expression, ExecutionContext executionContext, List<VariableAccess> variableAccesses)
{
boolean userChanged = checkFullyAuthenticatedUser(executionContext);
Object result = executeScript(expression, executionContext, variableAccesses);
if(userChanged)
{
AuthenticationUtil.clearCurrentSecurityContext();
}
return result;
}
private Object executeScript(String expression,
ExecutionContext executionContext,
List<VariableAccess> variableAccesses)
{
String user = AuthenticationUtil.getFullyAuthenticatedUser();
if (runas == null && user !=null)
{
return executeScript(executionContext, services, expression, variableAccesses, companyHome);
}
else
{
String runAsUser = runas;
if(runAsUser == null)
{
runAsUser = AuthenticationUtil.getSystemUserName();
}
else
{
validateRunAsUser();
}
return executeScriptAs(runAsUser, expression, executionContext, variableAccesses);
}
}
private Object executeScriptAs(String runAsUser,
final String expression,
final ExecutionContext executionContext,
final List<VariableAccess> variableAccesses)
{
// execute as specified runAsUser
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork() throws Exception
{
return executeScript(executionContext, services, expression, variableAccesses,companyHome);
}
}, runAsUser);
}
/**
* Checks a valid Fully Authenticated User is set.
* If none is set then attempts to set the task assignee as the Fully Authenticated User.
* @param executionContext
* @return <code>true</code> if the Fully Authenticated User was changes, otherwise <code>false</code>.
*/
private boolean checkFullyAuthenticatedUser(final ExecutionContext executionContext)
{
if(AuthenticationUtil.getFullyAuthenticatedUser()!= null)
return false;
TaskInstance taskInstance = executionContext.getTaskInstance();
if(taskInstance!=null)
{
String userName = taskInstance.getActorId();
if (userName != null)
{
AuthenticationUtil.setFullyAuthenticatedUser(userName);
return true;
}
}
return false;
}
/**
* Checks that the specified 'runas' field
* specifies a valid username.
*/
private void validateRunAsUser()
{
Boolean runAsExists = AuthenticationUtil.runAs(new RunAsWork<Boolean>()
{
// Validate using System user to ensure sufficient permissions available to access person node.
public Boolean doWork() throws Exception
{
return services.getPersonService().personExists(runas);
}
}, AuthenticationUtil.getSystemUserName());
if (!runAsExists)
{
throw new WorkflowException("runas user '" + runas + "' does not exist.");
}
}
/**
* Gets the expression {@link String} from the script.
* @param isTextOnly Is the script text only or is it XML?
* @return the expression {@link String}.
*/
private String getExpression(boolean isTextOnly)
{
if (isTextOnly)
{
return script.getText().trim();
}
else
{
Element expressionElement = script.element("expression");
if (expressionElement == null)
{
throw new WorkflowException("Script expression has not been provided");
}
return expressionElement.getText().trim();
}
}
@SuppressWarnings("unchecked")
private List<VariableAccess> getVariableAccessors(boolean isTextOnly)
{
if (isTextOnly)
{
return null;
}
else
{
return jpdlReader.readVariableAccesses(script);
}
}
/**
* Is the script specified as text only, or as explicit expression, variable elements
* @return boolean
*/
@SuppressWarnings("unchecked")
private boolean isScriptOnlyText()
{
Iterator<Element> iter = script.elementIterator();
while (iter.hasNext())
{
Element element = iter.next();
if (element.getNodeType() == org.dom4j.Node.ELEMENT_NODE)
{
return false;
}
}
return true;
}
/**
* Execute a script
*
* @param context jBPM execution context
* @param services Alfresco service registry
* @param expression script to execute
* @param variableAccesses (optional) list of jBPM variables to map into script (all, if not supplied)
* @param companyHome TODO
* @return script result
*/
public static Object executeScript(ExecutionContext context, ServiceRegistry services, String expression, List<VariableAccess> variableAccesses, NodeRef companyHome)
{
Map<String, Object> inputMap = createInputMap(services, companyHome, context, variableAccesses);
ScriptService scriptService = services.getScriptService();
scriptService.buildCoreModel(inputMap);
Object result = scriptService.executeScriptString(expression, inputMap);
result = convertForJBPM(result, services);
return result;
}
/**
* Convert values for JBPM Context
*
* @param value Object
* @param services ServiceRegistry
* @return Object
*/
@SuppressWarnings("unchecked")
private static Object convertForJBPM(Object value, ServiceRegistry services)
{
if (value == null)
{
return null;
}
else if (value instanceof NodeRef)
{
value = new JBPMNode(((NodeRef)value), services);
}
else if (value instanceof Collection)
{
// recursively convert each value in the collection
Collection<Object> collection = (Collection<Object>)value;
// Note: this needs to be cleaned up - we need to create appropriate collection type based
// on collection contents
boolean isNodeCollection = false;
for (Object obj : collection)
{
if (obj instanceof NodeRef)
{
isNodeCollection = true;
break;
}
}
if (isNodeCollection)
{
JBPMNodeList converted = new JBPMNodeList();
for (Object obj : collection)
{
if (!(obj instanceof NodeRef))
{
throw new WorkflowException("Unable to convert script collection to JBPM value - mixed node/non-node collection");
}
converted.add((JBPMNode)convertForJBPM(obj, services));
}
value = converted;
}
else
{
Collection<Object> converted = new ArrayList<Object>();
for (Object obj : collection)
{
converted.add(convertForJBPM(obj, services));
}
value = converted;
}
}
return value;
}
/**
* Construct map of arguments to pass to script
*
* Based on the <variable> elements of the action configuration.
* @param companyHome TODO
* @param executionContext the execution context
* @param variableAccesses the variable configuration
*
* @return the map of script arguments
*/
private static Map<String, Object> createInputMap(ServiceRegistry services, NodeRef companyHome, ExecutionContext executionContext, List<VariableAccess> variableAccesses)
{
ScriptService scriptService = services.getScriptService();
// initialise global script variables
NodeRef person = getPersonNode(services);
NodeRef userHome = null;
if (person != null)
{
NodeService nodeService = services.getNodeService();
userHome = (NodeRef)nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER);
}
Map<String, Object> inputMap = scriptService.buildDefaultModel(person, companyHome, userHome, null, null, null);
// initialise process variables
Token token = executionContext.getToken();
inputMap.put("executionContext", executionContext);
inputMap.put("token", token);
Node node = executionContext.getNode();
if (node != null)
{
inputMap.put("node", node);
}
Task task = executionContext.getTask();
if (task != null)
{
inputMap.put("task", task);
}
TaskInstance taskInstance = executionContext.getTaskInstance();
if (taskInstance != null)
{
inputMap.put("taskInstance", taskInstance);
}
// if no readable variableInstances are specified,
ContextInstance contextInstance = executionContext.getContextInstance();
if (!hasReadableVariable(variableAccesses))
{
// copy all the variableInstances of the context into the interpreter
Map<?, ?> 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;
}
private static NodeRef getPersonNode(ServiceRegistry services)
{
String userName = AuthenticationUtil.getFullyAuthenticatedUser();
if (userName != null)
{
NodeRef person = services.getPersonService().getPerson(userName);
return person;
}
return null;
}
/**
* Determine if there are variables to read from the process context
*
* @param variableAccesses the variables configuration
* @return true => there are variables to read
*/
private static 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 static VariableAccess getWritableVariable(List<VariableAccess> variableAccesses)
{
VariableAccess writable = null;
if (variableAccesses != null)
{
for (VariableAccess variableAccess : variableAccesses)
{
if (variableAccess.isWritable())
{
if (writable != null)
{
throw new WorkflowException("AlfrescoJavaScript supports only one writable variable");
}
writable = variableAccess;
}
}
}
return writable;
}
public void setScript(Element script)
{
this.script = script;
}
public void setRunas(String runas)
{
this.runas = runas;
}
}
package org.alfresco.repo.workflow.jbpm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
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.ScriptService;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.dom4j.Element;
import org.jbpm.context.def.VariableAccess;
import org.jbpm.context.exe.ContextInstance;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;
import org.jbpm.jpdl.xml.JpdlXmlReader;
import org.jbpm.taskmgmt.def.Task;
import org.jbpm.taskmgmt.exe.TaskInstance;
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>
* <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 ServiceRegistry services;
private NodeRef companyHome;
private Element script;
private String runas;
/**
* {@inheritDoc}
*/
@Override
protected void initialiseHandler(BeanFactory factory)
{
this.services = (ServiceRegistry)factory.getBean(ServiceRegistry.SERVICE_REGISTRY);
Repository repositoryHelper = (Repository)factory.getBean("repositoryHelper");
this.companyHome = repositoryHelper.getCompanyHome();
}
/* (non-Javadoc)
* @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
*/
public void execute(final ExecutionContext executionContext) throws Exception
{
// validate script
if (script == null)
{
throw new WorkflowException("Script has not been provided");
}
boolean isTextOnly = isScriptOnlyText();
List<VariableAccess> variableAccesses = getVariableAccessors(isTextOnly);
String expression = getExpression(isTextOnly);
// execute
Object result = executeExpression(expression, executionContext, variableAccesses);
// 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);
}
}
private Object executeExpression(String expression, ExecutionContext executionContext, List<VariableAccess> variableAccesses)
{
boolean userChanged = checkFullyAuthenticatedUser(executionContext);
Object result = executeScript(expression, executionContext, variableAccesses);
if(userChanged)
{
AuthenticationUtil.clearCurrentSecurityContext();
}
return result;
}
private Object executeScript(String expression,
ExecutionContext executionContext,
List<VariableAccess> variableAccesses)
{
String user = AuthenticationUtil.getFullyAuthenticatedUser();
if (runas == null && user !=null)
{
return executeScript(executionContext, services, expression, variableAccesses, companyHome);
}
else
{
String runAsUser = runas;
if(runAsUser == null)
{
runAsUser = AuthenticationUtil.getSystemUserName();
}
else
{
validateRunAsUser();
}
return executeScriptAs(runAsUser, expression, executionContext, variableAccesses);
}
}
private Object executeScriptAs(String runAsUser,
final String expression,
final ExecutionContext executionContext,
final List<VariableAccess> variableAccesses)
{
// execute as specified runAsUser
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork() throws Exception
{
return executeScript(executionContext, services, expression, variableAccesses,companyHome);
}
}, runAsUser);
}
/**
* Checks a valid Fully Authenticated User is set.
* If none is set then attempts to set the task assignee as the Fully Authenticated User.
* @param executionContext
* @return <code>true</code> if the Fully Authenticated User was changes, otherwise <code>false</code>.
*/
private boolean checkFullyAuthenticatedUser(final ExecutionContext executionContext)
{
if(AuthenticationUtil.getFullyAuthenticatedUser()!= null)
return false;
TaskInstance taskInstance = executionContext.getTaskInstance();
if(taskInstance!=null)
{
String userName = taskInstance.getActorId();
if (userName != null)
{
AuthenticationUtil.setFullyAuthenticatedUser(userName);
return true;
}
}
return false;
}
/**
* Checks that the specified 'runas' field
* specifies a valid username.
*/
private void validateRunAsUser()
{
Boolean runAsExists = AuthenticationUtil.runAs(new RunAsWork<Boolean>()
{
// Validate using System user to ensure sufficient permissions available to access person node.
public Boolean doWork() throws Exception
{
return services.getPersonService().personExists(runas);
}
}, AuthenticationUtil.getSystemUserName());
if (!runAsExists)
{
throw new WorkflowException("runas user '" + runas + "' does not exist.");
}
}
/**
* Gets the expression {@link String} from the script.
* @param isTextOnly Is the script text only or is it XML?
* @return the expression {@link String}.
*/
private String getExpression(boolean isTextOnly)
{
if (isTextOnly)
{
return script.getText().trim();
}
else
{
Element expressionElement = script.element("expression");
if (expressionElement == null)
{
throw new WorkflowException("Script expression has not been provided");
}
return expressionElement.getText().trim();
}
}
@SuppressWarnings("unchecked")
private List<VariableAccess> getVariableAccessors(boolean isTextOnly)
{
if (isTextOnly)
{
return null;
}
else
{
return jpdlReader.readVariableAccesses(script);
}
}
/**
* Is the script specified as text only, or as explicit expression, variable elements
* @return boolean
*/
@SuppressWarnings("unchecked")
private boolean isScriptOnlyText()
{
Iterator<Element> iter = script.elementIterator();
while (iter.hasNext())
{
Element element = iter.next();
if (element.getNodeType() == org.dom4j.Node.ELEMENT_NODE)
{
return false;
}
}
return true;
}
/**
* Execute a script
*
* @param context jBPM execution context
* @param services Alfresco service registry
* @param expression script to execute
* @param variableAccesses (optional) list of jBPM variables to map into script (all, if not supplied)
* @param companyHome TODO
* @return script result
*/
public static Object executeScript(ExecutionContext context, ServiceRegistry services, String expression, List<VariableAccess> variableAccesses, NodeRef companyHome)
{
Map<String, Object> inputMap = createInputMap(services, companyHome, context, variableAccesses);
ScriptService scriptService = services.getScriptService();
scriptService.buildCoreModel(inputMap);
Object result = scriptService.executeScriptString(expression, inputMap);
result = convertForJBPM(result, services);
return result;
}
/**
* Convert values for JBPM Context
*
* @param value Object
* @param services ServiceRegistry
* @return Object
*/
@SuppressWarnings("unchecked")
private static Object convertForJBPM(Object value, ServiceRegistry services)
{
if (value == null)
{
return null;
}
else if (value instanceof NodeRef)
{
value = new JBPMNode(((NodeRef)value), services);
}
else if (value instanceof Collection)
{
// recursively convert each value in the collection
Collection<Object> collection = (Collection<Object>)value;
// Note: this needs to be cleaned up - we need to create appropriate collection type based
// on collection contents
boolean isNodeCollection = false;
for (Object obj : collection)
{
if (obj instanceof NodeRef)
{
isNodeCollection = true;
break;
}
}
if (isNodeCollection)
{
JBPMNodeList converted = new JBPMNodeList();
for (Object obj : collection)
{
if (!(obj instanceof NodeRef))
{
throw new WorkflowException("Unable to convert script collection to JBPM value - mixed node/non-node collection");
}
converted.add((JBPMNode)convertForJBPM(obj, services));
}
value = converted;
}
else
{
Collection<Object> converted = new ArrayList<Object>();
for (Object obj : collection)
{
converted.add(convertForJBPM(obj, services));
}
value = converted;
}
}
return value;
}
/**
* Construct map of arguments to pass to script
*
* Based on the <variable> elements of the action configuration.
* @param companyHome TODO
* @param executionContext the execution context
* @param variableAccesses the variable configuration
*
* @return the map of script arguments
*/
private static Map<String, Object> createInputMap(ServiceRegistry services, NodeRef companyHome, ExecutionContext executionContext, List<VariableAccess> variableAccesses)
{
ScriptService scriptService = services.getScriptService();
// initialise global script variables
NodeRef person = getPersonNode(services);
NodeRef userHome = null;
if (person != null)
{
NodeService nodeService = services.getNodeService();
userHome = (NodeRef)nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER);
}
Map<String, Object> inputMap = scriptService.buildDefaultModel(person, companyHome, userHome, null, null, null);
// initialise process variables
Token token = executionContext.getToken();
inputMap.put("executionContext", executionContext);
inputMap.put("token", token);
Node node = executionContext.getNode();
if (node != null)
{
inputMap.put("node", node);
}
Task task = executionContext.getTask();
if (task != null)
{
inputMap.put("task", task);
}
TaskInstance taskInstance = executionContext.getTaskInstance();
if (taskInstance != null)
{
inputMap.put("taskInstance", taskInstance);
}
// if no readable variableInstances are specified,
ContextInstance contextInstance = executionContext.getContextInstance();
if (!hasReadableVariable(variableAccesses))
{
// copy all the variableInstances of the context into the interpreter
Map<?, ?> 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;
}
private static NodeRef getPersonNode(ServiceRegistry services)
{
String userName = AuthenticationUtil.getFullyAuthenticatedUser();
if (userName != null)
{
NodeRef person = services.getPersonService().getPerson(userName);
return person;
}
return null;
}
/**
* Determine if there are variables to read from the process context
*
* @param variableAccesses the variables configuration
* @return true => there are variables to read
*/
private static 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 static VariableAccess getWritableVariable(List<VariableAccess> variableAccesses)
{
VariableAccess writable = null;
if (variableAccesses != null)
{
for (VariableAccess variableAccess : variableAccesses)
{
if (variableAccess.isWritable())
{
if (writable != null)
{
throw new WorkflowException("AlfrescoJavaScript supports only one writable variable");
}
writable = variableAccess;
}
}
}
return writable;
}
public void setScript(Element script)
{
this.script = script;
}
public void setRunas(String runas)
{
this.runas = runas;
}
}

View File

@@ -1,203 +1,203 @@
package org.alfresco.repo.workflow.jbpm;
import java.io.InputStream;
import org.hibernate.SessionFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.configuration.ObjectFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
/**
* Implementation of Spring Module's JbpmConfigurationFactoryBean for Jbpm 3.2.
*
* @author Costin Leau
* @author davidc
*/
public class AlfrescoJbpmConfigurationFactoryBean implements InitializingBean, FactoryBean<JbpmConfiguration>,
BeanFactoryAware, BeanNameAware, DisposableBean
{
private JbpmConfiguration jbpmConfiguration;
private ObjectFactory objectFactory;
private Resource configuration;
private SessionFactory sessionFactory;
private String contextName = JbpmContext.DEFAULT_JBPM_CONTEXT_NAME;
/**
* FactoryLocator
*/
private final AlfrescoJbpmFactoryLocator factoryLocator = new AlfrescoJbpmFactoryLocator();
/*
* (non-Javadoc)
* @see
* org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org
* .springframework.beans.factory.BeanFactory)
*/
public void setBeanFactory(final BeanFactory beanFactory) throws BeansException
{
// TODO Added to get the build working. A better solution is needed
// long-term.
this.factoryLocator.destroy();
this.factoryLocator.setBeanFactory(beanFactory);
}
/**
* {@inheritDoc}
*/
public void setBeanName(final String name)
{
this.factoryLocator.setBeanName(name);
}
/**
* {@inheritDoc}
*/
public void afterPropertiesSet() throws Exception
{
if (this.configuration == null) { throw new IllegalArgumentException(
"configuration or objectFactory property need to be not null"); }
// 1. Construct Jbpm Configuration
// NOTE: Jbpm 3.2 adds a JbpmConfiguration value to its context
final InputStream stream = this.configuration.getInputStream();
this.jbpmConfiguration = JbpmConfiguration.parseInputStream(stream);
// 2. inject the HB session factory if it is the case
if (this.sessionFactory != null)
{
final JbpmContext context = this.jbpmConfiguration.createJbpmContext(this.contextName);
try
{
context.setSessionFactory(this.sessionFactory);
}
finally
{
context.close();
}
}
}
/**
* {@inheritDoc}
*/
public JbpmConfiguration getObject() throws Exception
{
return this.jbpmConfiguration;
}
/**
* {@inheritDoc}
*/
public Class<JbpmConfiguration> getObjectType()
{
return JbpmConfiguration.class;
}
/**
* {@inheritDoc}
*/
public boolean isSingleton()
{
return true;
}
/**
* @return Returns the configuration.
*/
public Resource getConfiguration()
{
return this.configuration;
}
/**
* @param configuration The configuration to set
*/
public void setConfiguration(final Resource configuration)
{
this.configuration = configuration;
}
/**
* @return Returns the objectFactory.
*/
public ObjectFactory getObjectFactory()
{
return this.objectFactory;
}
/**
* @param objectFactory The objectFactory to set
*/
public void setObjectFactory(final ObjectFactory objectFactory)
{
this.objectFactory = objectFactory;
}
/**
* @return Returns the contextName.
*/
public String getContextName()
{
return this.contextName;
}
/**
* @param contextName The contextName to set
*/
public void setContextName(final String contextName)
{
this.contextName = contextName;
}
/**
* @return Returns the sessionFactory.
*/
public SessionFactory getSessionFactory()
{
return this.sessionFactory;
}
/**
* @param sessionFactory The sessionFactory to set
*/
public void setSessionFactory(final SessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
/**
* {@inheritDoc}
*/
public void destroy() throws Exception
{
this.factoryLocator.destroy();
}
private static class AlfrescoJbpmFactoryLocator extends JbpmFactoryLocator
{
public void destroy()
{
JbpmFactoryLocator.beanFactories.clear();
JbpmFactoryLocator.beanFactoriesNames.clear();
JbpmFactoryLocator.referenceCounter.clear();
JbpmFactoryLocator.canUseDefaultBeanFactory = true;
JbpmFactoryLocator.defaultFactory = null;
}
}
}
package org.alfresco.repo.workflow.jbpm;
import java.io.InputStream;
import org.hibernate.SessionFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.configuration.ObjectFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
/**
* Implementation of Spring Module's JbpmConfigurationFactoryBean for Jbpm 3.2.
*
* @author Costin Leau
* @author davidc
*/
public class AlfrescoJbpmConfigurationFactoryBean implements InitializingBean, FactoryBean<JbpmConfiguration>,
BeanFactoryAware, BeanNameAware, DisposableBean
{
private JbpmConfiguration jbpmConfiguration;
private ObjectFactory objectFactory;
private Resource configuration;
private SessionFactory sessionFactory;
private String contextName = JbpmContext.DEFAULT_JBPM_CONTEXT_NAME;
/**
* FactoryLocator
*/
private final AlfrescoJbpmFactoryLocator factoryLocator = new AlfrescoJbpmFactoryLocator();
/*
* (non-Javadoc)
* @see
* org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org
* .springframework.beans.factory.BeanFactory)
*/
public void setBeanFactory(final BeanFactory beanFactory) throws BeansException
{
// TODO Added to get the build working. A better solution is needed
// long-term.
this.factoryLocator.destroy();
this.factoryLocator.setBeanFactory(beanFactory);
}
/**
* {@inheritDoc}
*/
public void setBeanName(final String name)
{
this.factoryLocator.setBeanName(name);
}
/**
* {@inheritDoc}
*/
public void afterPropertiesSet() throws Exception
{
if (this.configuration == null) { throw new IllegalArgumentException(
"configuration or objectFactory property need to be not null"); }
// 1. Construct Jbpm Configuration
// NOTE: Jbpm 3.2 adds a JbpmConfiguration value to its context
final InputStream stream = this.configuration.getInputStream();
this.jbpmConfiguration = JbpmConfiguration.parseInputStream(stream);
// 2. inject the HB session factory if it is the case
if (this.sessionFactory != null)
{
final JbpmContext context = this.jbpmConfiguration.createJbpmContext(this.contextName);
try
{
context.setSessionFactory(this.sessionFactory);
}
finally
{
context.close();
}
}
}
/**
* {@inheritDoc}
*/
public JbpmConfiguration getObject() throws Exception
{
return this.jbpmConfiguration;
}
/**
* {@inheritDoc}
*/
public Class<JbpmConfiguration> getObjectType()
{
return JbpmConfiguration.class;
}
/**
* {@inheritDoc}
*/
public boolean isSingleton()
{
return true;
}
/**
* @return Returns the configuration.
*/
public Resource getConfiguration()
{
return this.configuration;
}
/**
* @param configuration The configuration to set
*/
public void setConfiguration(final Resource configuration)
{
this.configuration = configuration;
}
/**
* @return Returns the objectFactory.
*/
public ObjectFactory getObjectFactory()
{
return this.objectFactory;
}
/**
* @param objectFactory The objectFactory to set
*/
public void setObjectFactory(final ObjectFactory objectFactory)
{
this.objectFactory = objectFactory;
}
/**
* @return Returns the contextName.
*/
public String getContextName()
{
return this.contextName;
}
/**
* @param contextName The contextName to set
*/
public void setContextName(final String contextName)
{
this.contextName = contextName;
}
/**
* @return Returns the sessionFactory.
*/
public SessionFactory getSessionFactory()
{
return this.sessionFactory;
}
/**
* @param sessionFactory The sessionFactory to set
*/
public void setSessionFactory(final SessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
/**
* {@inheritDoc}
*/
public void destroy() throws Exception
{
this.factoryLocator.destroy();
}
private static class AlfrescoJbpmFactoryLocator extends JbpmFactoryLocator
{
public void destroy()
{
JbpmFactoryLocator.beanFactories.clear();
JbpmFactoryLocator.beanFactoriesNames.clear();
JbpmFactoryLocator.referenceCounter.clear();
JbpmFactoryLocator.canUseDefaultBeanFactory = true;
JbpmFactoryLocator.defaultFactory = null;
}
}
}

View File

@@ -1,101 +1,101 @@
package org.alfresco.repo.workflow.jbpm;
import org.alfresco.repo.lock.JobLockService;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.job.executor.JobExecutor;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
/**
* jBPM Job Executor
*
* @author davidc
*/
public class AlfrescoJobExecutor extends JobExecutor
{
private static final long serialVersionUID = -4576396495395482111L;
private static Log log = LogFactory.getLog(JobExecutor.class);
private TransactionService transactionService;
private JbpmConfiguration jbpmConfiguration;
private JobLockService jobLockService;
private boolean jobExecutorLockEnabled = true;
public void setJobExecutorLockEnabled(boolean jobExecutorLockEnabled)
{
this.jobExecutorLockEnabled = jobExecutorLockEnabled;
}
/**
* Is Alfresco Job Executor Lock Enabled
*
* @return true if only one executor thread allowed (including across cluster)
*
* @since 3.2
*/
public boolean getJobExecutorLockEnabled()
{
return this.jobExecutorLockEnabled;
}
/**
* Gets Transaction Service
*
* @return transaction service
*/
public TransactionService getTransactionService()
{
return transactionService;
}
/**
* Gets Job Lock Service
*
* @return job lock service
*
* @since 3.2
*/
public JobLockService getJobLockService()
{
return jobLockService;
}
/**
* Constructor
*/
public AlfrescoJobExecutor()
{
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
transactionService = (TransactionService)factory.getFactory().getBean(ServiceRegistry.TRANSACTION_SERVICE.getLocalName());
jobLockService = (JobLockService)factory.getFactory().getBean(ServiceRegistry.JOB_LOCK_SERVICE.getLocalName());
jbpmConfiguration = (JbpmConfiguration)factory.getFactory().getBean("jbpm_configuration");
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
protected synchronized void startThread()
{
String threadName = getNextThreadName();
Thread thread = new AlfrescoJobExecutorThread(threadName, this, jbpmConfiguration, getIdleInterval(), getMaxIdleInterval(), getMaxLockTime(), getHistoryMaxSize());
getThreads().put(threadName, thread);
log.debug("starting new job executor thread '" + threadName + "'");
thread.setDaemon(true);
thread.start();
}
}
package org.alfresco.repo.workflow.jbpm;
import org.alfresco.repo.lock.JobLockService;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.job.executor.JobExecutor;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
/**
* jBPM Job Executor
*
* @author davidc
*/
public class AlfrescoJobExecutor extends JobExecutor
{
private static final long serialVersionUID = -4576396495395482111L;
private static Log log = LogFactory.getLog(JobExecutor.class);
private TransactionService transactionService;
private JbpmConfiguration jbpmConfiguration;
private JobLockService jobLockService;
private boolean jobExecutorLockEnabled = true;
public void setJobExecutorLockEnabled(boolean jobExecutorLockEnabled)
{
this.jobExecutorLockEnabled = jobExecutorLockEnabled;
}
/**
* Is Alfresco Job Executor Lock Enabled
*
* @return true if only one executor thread allowed (including across cluster)
*
* @since 3.2
*/
public boolean getJobExecutorLockEnabled()
{
return this.jobExecutorLockEnabled;
}
/**
* Gets Transaction Service
*
* @return transaction service
*/
public TransactionService getTransactionService()
{
return transactionService;
}
/**
* Gets Job Lock Service
*
* @return job lock service
*
* @since 3.2
*/
public JobLockService getJobLockService()
{
return jobLockService;
}
/**
* Constructor
*/
public AlfrescoJobExecutor()
{
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
transactionService = (TransactionService)factory.getFactory().getBean(ServiceRegistry.TRANSACTION_SERVICE.getLocalName());
jobLockService = (JobLockService)factory.getFactory().getBean(ServiceRegistry.JOB_LOCK_SERVICE.getLocalName());
jbpmConfiguration = (JbpmConfiguration)factory.getFactory().getBean("jbpm_configuration");
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
protected synchronized void startThread()
{
String threadName = getNextThreadName();
Thread thread = new AlfrescoJobExecutorThread(threadName, this, jbpmConfiguration, getIdleInterval(), getMaxIdleInterval(), getMaxLockTime(), getHistoryMaxSize());
getThreads().put(threadName, thread);
log.debug("starting new job executor thread '" + threadName + "'");
thread.setDaemon(true);
thread.start();
}
}

View File

@@ -1,448 +1,448 @@
package org.alfresco.repo.workflow.jbpm;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import org.alfresco.repo.lock.LockAcquisitionException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.DoNotRetryException;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.db.JobSession;
import org.jbpm.job.Job;
import org.jbpm.job.executor.JobExecutorThread;
import org.jbpm.persistence.JbpmPersistenceException;
import org.jbpm.svc.Services;
import org.jbpm.taskmgmt.exe.TaskInstance;
/**
* Alfresco Job Executor Thread
*
* @author davidc, janv
*/
public class AlfrescoJobExecutorThread extends JobExecutorThread
{
/**
* The name of the lock used to ensure that job executor does not run on
* more than one node at the same time.
*/
private static final QName LOCK_QNAME = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI,
"AlfrescoJbpmJobExecutor");
private static Log logger = LogFactory.getLog(AlfrescoJobExecutorThread.class);
private AlfrescoJobExecutor alfrescoJobExecutor;
private boolean isActive = true;
private long jbpmMaxLockTime;
private long jobLockTTL = 0;
private String jobLockToken = null;
private JbpmConfiguration jbpmConfiguration;
@Override
public void setActive(boolean isActive)
{
this.isActive = isActive;
}
/**
* Constructor
*/
public AlfrescoJobExecutorThread(String name, AlfrescoJobExecutor jobExecutor, JbpmConfiguration jbpmConfiguration,
int idleInterval, int maxIdleInterval, long maxLockTime, int maxHistory)
{
super(name, jobExecutor, jbpmConfiguration, idleInterval, maxIdleInterval, maxLockTime, maxHistory);
this.alfrescoJobExecutor = jobExecutor;
this.jbpmMaxLockTime = maxLockTime;
this.jobLockTTL = jbpmMaxLockTime + (1000 * 60 * 10);
this.jbpmConfiguration = jbpmConfiguration;
}
@SuppressWarnings("rawtypes")
@Override
protected Collection acquireJobs()
{
Collection jobs = Collections.EMPTY_LIST;
if ((isActive) && (!alfrescoJobExecutor.getTransactionService().isReadOnly()))
{
try
{
jobs = alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper()
.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Collection>()
{
public Collection execute() throws Throwable
{
if (jobLockToken != null)
{
refreshExecutorLock(jobLockToken);
}
else
{
jobLockToken = getExecutorLock();
}
try
{
return AlfrescoJobExecutorThread.super.acquireJobs();
}
catch (Throwable t)
{
logger.error("Failed to acquire jobs");
releaseExecutorLock(jobLockToken);
jobLockToken = null;
throw t;
}
}
});
if (jobs != null)
{
if (logger.isDebugEnabled() && (!logger.isTraceEnabled()) && (!jobs.isEmpty()))
{
logger.debug("acquired " + jobs.size() + " job" + ((jobs.size() != 1) ? "s" : ""));
}
if (logger.isTraceEnabled())
{
logger.trace("acquired " + jobs.size() + " job" + ((jobs.size() != 1) ? "s" : "")
+ ((jobs.size() > 0) ? ": " + jobs.toString() : ""));
}
if (jobs.size() == 0)
{
releaseExecutorLock(jobLockToken);
jobLockToken = null;
}
}
}
catch (LockAcquisitionException e)
{
// ignore
jobLockToken = null;
}
}
return jobs;
}
@Override
protected Date getNextDueDate()
{
if (!isActive)
{
return null;
}
return alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper()
.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Date>()
{
public Date execute() throws Throwable
{
return AlfrescoJobExecutorThread.super.getNextDueDate();
}
}, true);
}
/**
* {@inheritDoc}
*/
@Override
protected void executeJob(final Job jobIn)
{
// execute the job as System (ALF-10776) so transaction commit level
// operations have a security context.
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
executeJobImpl(jobIn);
return null;
}
}, getActorId(jobIn));
// clear authentication context for this thread
AuthenticationUtil.clearCurrentSecurityContext();
}
private String getActorId(final Job jobIn)
{
TaskInstance taskInstance = jobIn.getTaskInstance();
if (taskInstance != null)
{
String actorId = taskInstance.getActorId();
if (actorId != null && actorId.length() > 0)
{
return actorId;
}
}
return AuthenticationUtil.getSystemUserName();
}
private void executeJobImpl(final Job jobIn)
{
if ((!isActive) || (alfrescoJobExecutor.getTransactionService().isReadOnly()))
{
return;
}
// based on JBPM 3.3.1 (JobExecutorThread.executeJob)
// - wrap executeJob / deleteJob in Alfresco retries
// - add setRollbackOnly warnings
// - if Alfresco retries fail, attempt to set JBPM job exception/retries
try
{
RetryingTransactionHelper tranHelper = alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper();
tranHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try
{
JobSession jobSession = jbpmContext.getJobSession();
Job job = jobSession.loadJob(jobIn.getId());
if (logger.isTraceEnabled())
{
logger.trace("executing " + job);
}
if (job.execute(jbpmContext))
{
jobSession.deleteJob(job);
if (logger.isDebugEnabled())
{
logger.debug("executed and deleted: " + job);
}
}
// if this job is locked too long
long totalLockTimeInMillis = System.currentTimeMillis() - job.getLockTime().getTime();
if (totalLockTimeInMillis > jbpmMaxLockTime)
{
logger.warn("setRollbackOnly: exceeded maxLockTime (" + jbpmMaxLockTime + ") " + job);
jbpmContext.setRollbackOnly();
}
}
catch(Exception e)
{
if(isPersistenceException(e))
{
throw new AlfrescoJbpmPersistenceException(e);
}
else
{
throw e;
}
}
finally
{
jbpmContext.getSession().flush();
jbpmContext.close();
}
return null;
}
});
}
catch (LockAcquisitionException e)
{
// ignore
jobLockToken = null;
}
catch(JbpmPersistenceException pe)
{
if(Services.isCausedByStaleState(pe))
{
if (logger.isDebugEnabled())
{
logger.debug("optimistic locking failed, couldn't complete job "+ jobIn, pe);
}
}
else handleException(jobIn, pe);
}
catch (final Exception e)
{
handleException(jobIn, e);
}
}
private void handleException(final Job jobIn, final Exception e)
{
if (logger.isErrorEnabled())
{
logger.error("failed to execute " + jobIn, e);
}
try
{
RetryingTransactionHelper tranHelper = alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper();
tranHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try
{
JobSession jobSession = jbpmContext.getJobSession();
Job job = jobSession.loadJob(jobIn.getId());
StringWriter memoryWriter = new StringWriter();
e.printStackTrace(new PrintWriter(memoryWriter));
job.setException(memoryWriter.toString());
if (logger.isDebugEnabled())
{
logger.debug("attempting to update exception/retries: " + job);
}
int retries = 0;
if (isPersistenceException(e) ==false)
{
retries = job.getRetries() -1;
}
job.setRetries(retries);
if (logger.isInfoEnabled())
{
String msg = "updated job exception and set to " + job.getRetries() + " retries: " + jobIn;
logger.info(msg);
}
}
finally
{
jbpmContext.getSession().flush();
jbpmContext.close();
}
return null;
}
});
}
catch (Exception e2)
{
if (logger.isErrorEnabled())
{
logger.error("failed to update job exception/retries " + jobIn, e2);
}
}
}
private String getExecutorLock()
{
String lockToken = null;
if (alfrescoJobExecutor.getJobExecutorLockEnabled())
{
try
{
lockToken = alfrescoJobExecutor.getJobLockService().getLock(LOCK_QNAME, jobLockTTL, 3000, 10);
if (logger.isTraceEnabled())
{
logger.trace(Thread.currentThread().getName() + " got lock token: " + lockToken);
}
}
catch (LockAcquisitionException e)
{
if (logger.isTraceEnabled())
{
logger.trace("Failed to get Alfresco Job Executor lock - may already running in another thread");
}
throw e;
}
}
return lockToken;
}
private void refreshExecutorLock(String lockToken)
{
if (lockToken != null)
{
try
{
alfrescoJobExecutor.getJobLockService().refreshLock(lockToken, LOCK_QNAME, jobLockTTL);
if (logger.isTraceEnabled())
{
logger.trace(Thread.currentThread().getName() + " refreshed lock token: " + lockToken);
}
}
catch (LockAcquisitionException e)
{
if (logger.isTraceEnabled())
{
logger.trace("Failed to refresh Alfresco Job Executor lock - may no longer exist (" + lockToken
+ ")");
}
throw e;
}
}
}
private void releaseExecutorLock(String lockToken)
{
if (lockToken != null)
{
try
{
alfrescoJobExecutor.getJobLockService().releaseLock(lockToken, LOCK_QNAME);
if (logger.isTraceEnabled())
{
logger.trace(Thread.currentThread().getName() + " released lock token: " + lockToken);
}
}
catch (LockAcquisitionException e)
{
if (logger.isTraceEnabled())
{
logger.trace("Failed to release Alfresco Job Executor lock - may no longer exist (" + lockToken
+ ")");
}
throw e;
}
}
}
private boolean isPersistenceException(Throwable throwable)
{
do
{
if (throwable instanceof HibernateException)
{
return true;
}
throwable = throwable.getCause();
}
while (throwable != null);
return false;
}
public static class AlfrescoJbpmPersistenceException extends Exception implements DoNotRetryException
{
private static final long serialVersionUID = -2233119713831272158L;
public AlfrescoJbpmPersistenceException(Throwable cause) {
super(cause);
}
}
}
package org.alfresco.repo.workflow.jbpm;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import org.alfresco.repo.lock.LockAcquisitionException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.DoNotRetryException;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.db.JobSession;
import org.jbpm.job.Job;
import org.jbpm.job.executor.JobExecutorThread;
import org.jbpm.persistence.JbpmPersistenceException;
import org.jbpm.svc.Services;
import org.jbpm.taskmgmt.exe.TaskInstance;
/**
* Alfresco Job Executor Thread
*
* @author davidc, janv
*/
public class AlfrescoJobExecutorThread extends JobExecutorThread
{
/**
* The name of the lock used to ensure that job executor does not run on
* more than one node at the same time.
*/
private static final QName LOCK_QNAME = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI,
"AlfrescoJbpmJobExecutor");
private static Log logger = LogFactory.getLog(AlfrescoJobExecutorThread.class);
private AlfrescoJobExecutor alfrescoJobExecutor;
private boolean isActive = true;
private long jbpmMaxLockTime;
private long jobLockTTL = 0;
private String jobLockToken = null;
private JbpmConfiguration jbpmConfiguration;
@Override
public void setActive(boolean isActive)
{
this.isActive = isActive;
}
/**
* Constructor
*/
public AlfrescoJobExecutorThread(String name, AlfrescoJobExecutor jobExecutor, JbpmConfiguration jbpmConfiguration,
int idleInterval, int maxIdleInterval, long maxLockTime, int maxHistory)
{
super(name, jobExecutor, jbpmConfiguration, idleInterval, maxIdleInterval, maxLockTime, maxHistory);
this.alfrescoJobExecutor = jobExecutor;
this.jbpmMaxLockTime = maxLockTime;
this.jobLockTTL = jbpmMaxLockTime + (1000 * 60 * 10);
this.jbpmConfiguration = jbpmConfiguration;
}
@SuppressWarnings("rawtypes")
@Override
protected Collection acquireJobs()
{
Collection jobs = Collections.EMPTY_LIST;
if ((isActive) && (!alfrescoJobExecutor.getTransactionService().isReadOnly()))
{
try
{
jobs = alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper()
.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Collection>()
{
public Collection execute() throws Throwable
{
if (jobLockToken != null)
{
refreshExecutorLock(jobLockToken);
}
else
{
jobLockToken = getExecutorLock();
}
try
{
return AlfrescoJobExecutorThread.super.acquireJobs();
}
catch (Throwable t)
{
logger.error("Failed to acquire jobs");
releaseExecutorLock(jobLockToken);
jobLockToken = null;
throw t;
}
}
});
if (jobs != null)
{
if (logger.isDebugEnabled() && (!logger.isTraceEnabled()) && (!jobs.isEmpty()))
{
logger.debug("acquired " + jobs.size() + " job" + ((jobs.size() != 1) ? "s" : ""));
}
if (logger.isTraceEnabled())
{
logger.trace("acquired " + jobs.size() + " job" + ((jobs.size() != 1) ? "s" : "")
+ ((jobs.size() > 0) ? ": " + jobs.toString() : ""));
}
if (jobs.size() == 0)
{
releaseExecutorLock(jobLockToken);
jobLockToken = null;
}
}
}
catch (LockAcquisitionException e)
{
// ignore
jobLockToken = null;
}
}
return jobs;
}
@Override
protected Date getNextDueDate()
{
if (!isActive)
{
return null;
}
return alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper()
.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Date>()
{
public Date execute() throws Throwable
{
return AlfrescoJobExecutorThread.super.getNextDueDate();
}
}, true);
}
/**
* {@inheritDoc}
*/
@Override
protected void executeJob(final Job jobIn)
{
// execute the job as System (ALF-10776) so transaction commit level
// operations have a security context.
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
executeJobImpl(jobIn);
return null;
}
}, getActorId(jobIn));
// clear authentication context for this thread
AuthenticationUtil.clearCurrentSecurityContext();
}
private String getActorId(final Job jobIn)
{
TaskInstance taskInstance = jobIn.getTaskInstance();
if (taskInstance != null)
{
String actorId = taskInstance.getActorId();
if (actorId != null && actorId.length() > 0)
{
return actorId;
}
}
return AuthenticationUtil.getSystemUserName();
}
private void executeJobImpl(final Job jobIn)
{
if ((!isActive) || (alfrescoJobExecutor.getTransactionService().isReadOnly()))
{
return;
}
// based on JBPM 3.3.1 (JobExecutorThread.executeJob)
// - wrap executeJob / deleteJob in Alfresco retries
// - add setRollbackOnly warnings
// - if Alfresco retries fail, attempt to set JBPM job exception/retries
try
{
RetryingTransactionHelper tranHelper = alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper();
tranHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try
{
JobSession jobSession = jbpmContext.getJobSession();
Job job = jobSession.loadJob(jobIn.getId());
if (logger.isTraceEnabled())
{
logger.trace("executing " + job);
}
if (job.execute(jbpmContext))
{
jobSession.deleteJob(job);
if (logger.isDebugEnabled())
{
logger.debug("executed and deleted: " + job);
}
}
// if this job is locked too long
long totalLockTimeInMillis = System.currentTimeMillis() - job.getLockTime().getTime();
if (totalLockTimeInMillis > jbpmMaxLockTime)
{
logger.warn("setRollbackOnly: exceeded maxLockTime (" + jbpmMaxLockTime + ") " + job);
jbpmContext.setRollbackOnly();
}
}
catch(Exception e)
{
if(isPersistenceException(e))
{
throw new AlfrescoJbpmPersistenceException(e);
}
else
{
throw e;
}
}
finally
{
jbpmContext.getSession().flush();
jbpmContext.close();
}
return null;
}
});
}
catch (LockAcquisitionException e)
{
// ignore
jobLockToken = null;
}
catch(JbpmPersistenceException pe)
{
if(Services.isCausedByStaleState(pe))
{
if (logger.isDebugEnabled())
{
logger.debug("optimistic locking failed, couldn't complete job "+ jobIn, pe);
}
}
else handleException(jobIn, pe);
}
catch (final Exception e)
{
handleException(jobIn, e);
}
}
private void handleException(final Job jobIn, final Exception e)
{
if (logger.isErrorEnabled())
{
logger.error("failed to execute " + jobIn, e);
}
try
{
RetryingTransactionHelper tranHelper = alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper();
tranHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try
{
JobSession jobSession = jbpmContext.getJobSession();
Job job = jobSession.loadJob(jobIn.getId());
StringWriter memoryWriter = new StringWriter();
e.printStackTrace(new PrintWriter(memoryWriter));
job.setException(memoryWriter.toString());
if (logger.isDebugEnabled())
{
logger.debug("attempting to update exception/retries: " + job);
}
int retries = 0;
if (isPersistenceException(e) ==false)
{
retries = job.getRetries() -1;
}
job.setRetries(retries);
if (logger.isInfoEnabled())
{
String msg = "updated job exception and set to " + job.getRetries() + " retries: " + jobIn;
logger.info(msg);
}
}
finally
{
jbpmContext.getSession().flush();
jbpmContext.close();
}
return null;
}
});
}
catch (Exception e2)
{
if (logger.isErrorEnabled())
{
logger.error("failed to update job exception/retries " + jobIn, e2);
}
}
}
private String getExecutorLock()
{
String lockToken = null;
if (alfrescoJobExecutor.getJobExecutorLockEnabled())
{
try
{
lockToken = alfrescoJobExecutor.getJobLockService().getLock(LOCK_QNAME, jobLockTTL, 3000, 10);
if (logger.isTraceEnabled())
{
logger.trace(Thread.currentThread().getName() + " got lock token: " + lockToken);
}
}
catch (LockAcquisitionException e)
{
if (logger.isTraceEnabled())
{
logger.trace("Failed to get Alfresco Job Executor lock - may already running in another thread");
}
throw e;
}
}
return lockToken;
}
private void refreshExecutorLock(String lockToken)
{
if (lockToken != null)
{
try
{
alfrescoJobExecutor.getJobLockService().refreshLock(lockToken, LOCK_QNAME, jobLockTTL);
if (logger.isTraceEnabled())
{
logger.trace(Thread.currentThread().getName() + " refreshed lock token: " + lockToken);
}
}
catch (LockAcquisitionException e)
{
if (logger.isTraceEnabled())
{
logger.trace("Failed to refresh Alfresco Job Executor lock - may no longer exist (" + lockToken
+ ")");
}
throw e;
}
}
}
private void releaseExecutorLock(String lockToken)
{
if (lockToken != null)
{
try
{
alfrescoJobExecutor.getJobLockService().releaseLock(lockToken, LOCK_QNAME);
if (logger.isTraceEnabled())
{
logger.trace(Thread.currentThread().getName() + " released lock token: " + lockToken);
}
}
catch (LockAcquisitionException e)
{
if (logger.isTraceEnabled())
{
logger.trace("Failed to release Alfresco Job Executor lock - may no longer exist (" + lockToken
+ ")");
}
throw e;
}
}
}
private boolean isPersistenceException(Throwable throwable)
{
do
{
if (throwable instanceof HibernateException)
{
return true;
}
throwable = throwable.getCause();
}
while (throwable != null);
return false;
}
public static class AlfrescoJbpmPersistenceException extends Exception implements DoNotRetryException
{
private static final long serialVersionUID = -2233119713831272158L;
public AlfrescoJbpmPersistenceException(Throwable cause) {
super(cause);
}
}
}

View File

@@ -1,74 +1,74 @@
package org.alfresco.repo.workflow.jbpm;
import org.jbpm.JbpmContext;
import org.jbpm.graph.exe.Token;
import org.jbpm.job.Timer;
import org.jbpm.taskmgmt.exe.TaskInstance;
/**
* Extended JBPM Timer that provides Alfresco context.
*
* NOTE: The action triggered by the timer is executed as the user assigned
* to the task associated with the timer. If not associated with a
* task, the timer is executed unauthenticated.
*
* @author davidc
* @author Nick Smith
*/
public class AlfrescoTimer extends Timer
{
private static final long serialVersionUID = -6618486175822866286L;
/**
* Construct
*/
public AlfrescoTimer()
{
super();
}
/**
* Construct
*
* @param token Token
*/
public AlfrescoTimer(Token token)
{
super(token);
}
/**
* {@inheritDoc}
*/
@Override
public boolean execute(final JbpmContext jbpmContext)
throws Exception
{
// establish authentication context
final TaskInstance taskInstance = getTaskInstance();
// execute timer
boolean deleteTimer = AlfrescoTimer.super.execute(jbpmContext);
// End the task if timer does not repeat.
// Note the order is a little odd here as the task will be ended
// after the token has been signalled to move to the next node.
if (deleteTimer
&& taskInstance != null
&& taskInstance.isOpen())
{
taskInstance.setSignalling(false);
String transitionName = getTransitionName();
if (transitionName==null)
{
taskInstance.end();
}
else
{
taskInstance.end(transitionName);
}
}
return deleteTimer;
}
}
package org.alfresco.repo.workflow.jbpm;
import org.jbpm.JbpmContext;
import org.jbpm.graph.exe.Token;
import org.jbpm.job.Timer;
import org.jbpm.taskmgmt.exe.TaskInstance;
/**
* Extended JBPM Timer that provides Alfresco context.
*
* NOTE: The action triggered by the timer is executed as the user assigned
* to the task associated with the timer. If not associated with a
* task, the timer is executed unauthenticated.
*
* @author davidc
* @author Nick Smith
*/
public class AlfrescoTimer extends Timer
{
private static final long serialVersionUID = -6618486175822866286L;
/**
* Construct
*/
public AlfrescoTimer()
{
super();
}
/**
* Construct
*
* @param token Token
*/
public AlfrescoTimer(Token token)
{
super(token);
}
/**
* {@inheritDoc}
*/
@Override
public boolean execute(final JbpmContext jbpmContext)
throws Exception
{
// establish authentication context
final TaskInstance taskInstance = getTaskInstance();
// execute timer
boolean deleteTimer = AlfrescoTimer.super.execute(jbpmContext);
// End the task if timer does not repeat.
// Note the order is a little odd here as the task will be ended
// after the token has been signalled to move to the next node.
if (deleteTimer
&& taskInstance != null
&& taskInstance.isOpen())
{
taskInstance.setSignalling(false);
String transitionName = getTransitionName();
if (transitionName==null)
{
taskInstance.end();
}
else
{
taskInstance.end(transitionName);
}
}
return deleteTimer;
}
}

View File

@@ -1,243 +1,243 @@
package org.alfresco.repo.workflow.jbpm;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.dom4j.Element;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.Transition;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;
import org.jbpm.instantiation.FieldInstantiator;
import org.springframework.beans.factory.BeanFactory;
/**
* For each "item in collection", create a fork.
*/
public class ForEachFork extends JBPMSpringActionHandler
{
private static final long serialVersionUID = 4643103713602441652L;
private ServiceRegistry services;
private Element foreach;
private String var;
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler#initialiseHandler(org.springframework.beans.factory.BeanFactory)
*/
@Override
protected void initialiseHandler(BeanFactory factory)
{
services = (ServiceRegistry)factory.getBean(ServiceRegistry.SERVICE_REGISTRY);
}
/**
* Create a new child token for each item in list.
*
* @param executionContext ExecutionContext
* @throws Exception
*/
public void execute(final ExecutionContext executionContext)
throws Exception
{
//
// process action handler arguments
//
if (foreach == null)
{
throw new WorkflowException("forEach has not been provided");
}
// Collection<?> forEachColl = buildForEachCollection(executionContext);
if (var == null || var.length() == 0)
{
throw new WorkflowException("forEach variable name has not been provided");
}
//
// create forked paths
//
Node node = executionContext.getNode();
List<ForkedTransition> forkTransitions = new ArrayList<ForkedTransition>();
Collection<?> forEachColl = buildForEachCollection(executionContext);
// Create a new token and execution context for each node transition and item in list
List<Transition> nodeTransitions = node.getLeavingTransitions();
for (Transition noderansition : nodeTransitions)
{
int iVar = 0;
for (Object item: forEachColl)
{
// create child token to represent new path
Token loopToken = buildChildToken(executionContext, noderansition, iVar);
iVar++;
// assign variable within path
final ExecutionContext newExecutionContext = new ExecutionContext(loopToken);
newExecutionContext.getContextInstance().createVariable(var, item, loopToken);
// record path & transition
ForkedTransition forkTransition = new ForkedTransition();
forkTransition.executionContext = newExecutionContext;
forkTransition.transition = noderansition;
forkTransitions.add(forkTransition);
}
}
//
// let each new token leave the node.
//
for (ForkedTransition forkTransition : forkTransitions)
{
node.leave(forkTransition.executionContext, forkTransition.transition);
}
}
private Token buildChildToken(final ExecutionContext executionContext, Transition noderansition,
int iVar)
{
Token rootToken = executionContext.getToken();
String tokenName = getTokenName(rootToken, noderansition.getName(), iVar);
Token loopToken = new Token(rootToken, tokenName);
loopToken.setTerminationImplicit(true);
executionContext.getJbpmContext().getSession().save(loopToken);
return loopToken;
}
private Collection<?> buildForEachCollection(final ExecutionContext executionContext)
{
// build "for each" collection
String text = foreach.getTextTrim();
if (text != null && text.startsWith("#{"))
{
return evaluateForEachExpression(executionContext, text);
}
return (Collection<?>) FieldInstantiator.getValue(List.class, foreach);
}
private Collection<?> evaluateForEachExpression(final ExecutionContext executionContext, String forEachText)
{
String expression = forEachText.substring(2, forEachText.length() -1);
Object result = AlfrescoJavaScript.executeScript(executionContext, services, expression, null, null);
if (result == null)
{
throw new WorkflowException("forEach expression '" + forEachText + "' evaluates to null");
}
// expression evaluates to string
if (result instanceof String)
{
return buildStrings((String)result);
}
// expression evaluates to Node array
else if (result instanceof Serializable[])
{
return buildJbpmNodes((Serializable[]) result);
}
// expression evaluates to collection
else if (result instanceof Collection<?>)
{
return (Collection<?>)result;
}
else return null;
}
private List<?> buildStrings(String result)
{
String[] results = result.trim().split(",");
return Arrays.asList(results);
}
private List<?> buildJbpmNodes(Serializable[] nodes)
{
List<JBPMNode> jbpmNodes = new ArrayList<JBPMNode>(nodes.length);
for (Serializable node : nodes)
{
if (node instanceof NodeRef)
{
JBPMNode jbpmNode = new JBPMNode((NodeRef)node, services);
jbpmNodes.add(jbpmNode);
}
}
return jbpmNodes;
}
/**
* Create a token name
*
* @param parent Token
* @param transitionName String
* @param loopIndex int
* @return String
*/
protected String getTokenName(Token parent, String transitionName, int loopIndex)
{
String suffix = "." + loopIndex;
if (transitionName == null || transitionName.isEmpty())
{
// No transition name
int size = (parent.getChildren() != null) ? parent.getChildren().size() + 1 : 1;
return buildTokenName("FOREACHFORK", suffix, size);
}
return findFirstAvailableTokenName(parent, transitionName, suffix);
}
private String findFirstAvailableTokenName(Token parent, String transitionName, String suffix)
{
int i = 1;
while (true)
{
String tokenName = buildTokenName(transitionName, suffix, i);
if(!parent.hasChild(tokenName))
{
return tokenName;
}
i++;
}
}
private String buildTokenName(String prefix, String suffix, int count)
{
String countStr = count<2 ? "": Integer.toString(count);
return prefix + countStr + suffix;
}
/**
* Sets the list of objects to be iterated over.
* @param foreach the list of objects to set
*/
public void setForeach(Element foreach)
{
this.foreach = foreach;
}
/**
* Set the name of the variable to which the eleements of <code>foreach</code> are assigned.
* @param var the variable name to set
*/
public void setVar(String var)
{
this.var = var;
}
/**
* Fork Transition
*/
private class ForkedTransition
{
private ExecutionContext executionContext;
private Transition transition;
}
}
package org.alfresco.repo.workflow.jbpm;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.dom4j.Element;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.Transition;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;
import org.jbpm.instantiation.FieldInstantiator;
import org.springframework.beans.factory.BeanFactory;
/**
* For each "item in collection", create a fork.
*/
public class ForEachFork extends JBPMSpringActionHandler
{
private static final long serialVersionUID = 4643103713602441652L;
private ServiceRegistry services;
private Element foreach;
private String var;
/* (non-Javadoc)
* @see org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler#initialiseHandler(org.springframework.beans.factory.BeanFactory)
*/
@Override
protected void initialiseHandler(BeanFactory factory)
{
services = (ServiceRegistry)factory.getBean(ServiceRegistry.SERVICE_REGISTRY);
}
/**
* Create a new child token for each item in list.
*
* @param executionContext ExecutionContext
* @throws Exception
*/
public void execute(final ExecutionContext executionContext)
throws Exception
{
//
// process action handler arguments
//
if (foreach == null)
{
throw new WorkflowException("forEach has not been provided");
}
// Collection<?> forEachColl = buildForEachCollection(executionContext);
if (var == null || var.length() == 0)
{
throw new WorkflowException("forEach variable name has not been provided");
}
//
// create forked paths
//
Node node = executionContext.getNode();
List<ForkedTransition> forkTransitions = new ArrayList<ForkedTransition>();
Collection<?> forEachColl = buildForEachCollection(executionContext);
// Create a new token and execution context for each node transition and item in list
List<Transition> nodeTransitions = node.getLeavingTransitions();
for (Transition noderansition : nodeTransitions)
{
int iVar = 0;
for (Object item: forEachColl)
{
// create child token to represent new path
Token loopToken = buildChildToken(executionContext, noderansition, iVar);
iVar++;
// assign variable within path
final ExecutionContext newExecutionContext = new ExecutionContext(loopToken);
newExecutionContext.getContextInstance().createVariable(var, item, loopToken);
// record path & transition
ForkedTransition forkTransition = new ForkedTransition();
forkTransition.executionContext = newExecutionContext;
forkTransition.transition = noderansition;
forkTransitions.add(forkTransition);
}
}
//
// let each new token leave the node.
//
for (ForkedTransition forkTransition : forkTransitions)
{
node.leave(forkTransition.executionContext, forkTransition.transition);
}
}
private Token buildChildToken(final ExecutionContext executionContext, Transition noderansition,
int iVar)
{
Token rootToken = executionContext.getToken();
String tokenName = getTokenName(rootToken, noderansition.getName(), iVar);
Token loopToken = new Token(rootToken, tokenName);
loopToken.setTerminationImplicit(true);
executionContext.getJbpmContext().getSession().save(loopToken);
return loopToken;
}
private Collection<?> buildForEachCollection(final ExecutionContext executionContext)
{
// build "for each" collection
String text = foreach.getTextTrim();
if (text != null && text.startsWith("#{"))
{
return evaluateForEachExpression(executionContext, text);
}
return (Collection<?>) FieldInstantiator.getValue(List.class, foreach);
}
private Collection<?> evaluateForEachExpression(final ExecutionContext executionContext, String forEachText)
{
String expression = forEachText.substring(2, forEachText.length() -1);
Object result = AlfrescoJavaScript.executeScript(executionContext, services, expression, null, null);
if (result == null)
{
throw new WorkflowException("forEach expression '" + forEachText + "' evaluates to null");
}
// expression evaluates to string
if (result instanceof String)
{
return buildStrings((String)result);
}
// expression evaluates to Node array
else if (result instanceof Serializable[])
{
return buildJbpmNodes((Serializable[]) result);
}
// expression evaluates to collection
else if (result instanceof Collection<?>)
{
return (Collection<?>)result;
}
else return null;
}
private List<?> buildStrings(String result)
{
String[] results = result.trim().split(",");
return Arrays.asList(results);
}
private List<?> buildJbpmNodes(Serializable[] nodes)
{
List<JBPMNode> jbpmNodes = new ArrayList<JBPMNode>(nodes.length);
for (Serializable node : nodes)
{
if (node instanceof NodeRef)
{
JBPMNode jbpmNode = new JBPMNode((NodeRef)node, services);
jbpmNodes.add(jbpmNode);
}
}
return jbpmNodes;
}
/**
* Create a token name
*
* @param parent Token
* @param transitionName String
* @param loopIndex int
* @return String
*/
protected String getTokenName(Token parent, String transitionName, int loopIndex)
{
String suffix = "." + loopIndex;
if (transitionName == null || transitionName.isEmpty())
{
// No transition name
int size = (parent.getChildren() != null) ? parent.getChildren().size() + 1 : 1;
return buildTokenName("FOREACHFORK", suffix, size);
}
return findFirstAvailableTokenName(parent, transitionName, suffix);
}
private String findFirstAvailableTokenName(Token parent, String transitionName, String suffix)
{
int i = 1;
while (true)
{
String tokenName = buildTokenName(transitionName, suffix, i);
if(!parent.hasChild(tokenName))
{
return tokenName;
}
i++;
}
}
private String buildTokenName(String prefix, String suffix, int count)
{
String countStr = count<2 ? "": Integer.toString(count);
return prefix + countStr + suffix;
}
/**
* Sets the list of objects to be iterated over.
* @param foreach the list of objects to set
*/
public void setForeach(Element foreach)
{
this.foreach = foreach;
}
/**
* Set the name of the variable to which the eleements of <code>foreach</code> are assigned.
* @param var the variable name to set
*/
public void setVar(String var)
{
this.var = var;
}
/**
* Fork Transition
*/
private class ForkedTransition
{
private ExecutionContext executionContext;
private Transition transition;
}
}

View File

@@ -1,61 +1,61 @@
package org.alfresco.repo.workflow.jbpm;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.jpdl.JpdlException;
import org.jbpm.jpdl.par.ProcessArchive;
import org.jbpm.jpdl.par.ProcessArchiveParser;
import org.jbpm.jpdl.xml.JpdlXmlReader;
import org.xml.sax.InputSource;
/**
* Alfresco specific process archive parser to allow for extensions
* to jPDL.
*
* @author davidc
*/
public class JBPMJpdlArchiveParser implements ProcessArchiveParser
{
private static final long serialVersionUID = 1L;
/* (non-Javadoc)
* @see org.jbpm.jpdl.par.ProcessArchiveParser#readFromArchive(org.jbpm.jpdl.par.ProcessArchive, org.jbpm.graph.def.ProcessDefinition)
*/
public ProcessDefinition readFromArchive(ProcessArchive processArchive, ProcessDefinition processDefinition)
throws JpdlException
{
// NOTE: This method implementation is a copy from the JpdlXmlReader class
// with the difference of constructing an AlfrescoCreateTimerAction.
// It may need to be updated whenever a jbpm library upgrade is performed.
try
{
byte[] processBytes = processArchive.getEntry("processdefinition.xml");
if (processBytes == null)
{
throw new JpdlException("no processdefinition.xml inside process archive");
}
// creating the JpdlXmlReader
InputStream processInputStream = new ByteArrayInputStream(processBytes);
InputSource processInputSource = new InputSource(processInputStream);
JpdlXmlReader jpdlXmlReader = new JBPMJpdlXmlReader(processInputSource, processArchive);
processDefinition = jpdlXmlReader.readProcessDefinition();
// close all the streams
jpdlXmlReader.close();
processInputStream.close();
}
catch (IOException e)
{
throw new JpdlException("io problem while reading processdefinition.xml: " + e.getMessage(), e);
}
return processDefinition;
}
}
package org.alfresco.repo.workflow.jbpm;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.jpdl.JpdlException;
import org.jbpm.jpdl.par.ProcessArchive;
import org.jbpm.jpdl.par.ProcessArchiveParser;
import org.jbpm.jpdl.xml.JpdlXmlReader;
import org.xml.sax.InputSource;
/**
* Alfresco specific process archive parser to allow for extensions
* to jPDL.
*
* @author davidc
*/
public class JBPMJpdlArchiveParser implements ProcessArchiveParser
{
private static final long serialVersionUID = 1L;
/* (non-Javadoc)
* @see org.jbpm.jpdl.par.ProcessArchiveParser#readFromArchive(org.jbpm.jpdl.par.ProcessArchive, org.jbpm.graph.def.ProcessDefinition)
*/
public ProcessDefinition readFromArchive(ProcessArchive processArchive, ProcessDefinition processDefinition)
throws JpdlException
{
// NOTE: This method implementation is a copy from the JpdlXmlReader class
// with the difference of constructing an AlfrescoCreateTimerAction.
// It may need to be updated whenever a jbpm library upgrade is performed.
try
{
byte[] processBytes = processArchive.getEntry("processdefinition.xml");
if (processBytes == null)
{
throw new JpdlException("no processdefinition.xml inside process archive");
}
// creating the JpdlXmlReader
InputStream processInputStream = new ByteArrayInputStream(processBytes);
InputSource processInputSource = new InputSource(processInputStream);
JpdlXmlReader jpdlXmlReader = new JBPMJpdlXmlReader(processInputSource, processArchive);
processDefinition = jpdlXmlReader.readProcessDefinition();
// close all the streams
jpdlXmlReader.close();
processInputStream.close();
}
catch (IOException e)
{
throw new JpdlException("io problem while reading processdefinition.xml: " + e.getMessage(), e);
}
return processDefinition;
}
}

View File

@@ -1,155 +1,155 @@
package org.alfresco.repo.workflow.jbpm;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;
import org.dom4j.Element;
import org.jbpm.graph.def.Action;
import org.jbpm.graph.def.Event;
import org.jbpm.graph.def.Node;
import org.jbpm.instantiation.Delegation;
import org.jbpm.jpdl.xml.JpdlXmlReader;
import org.jbpm.jpdl.xml.Problem;
import org.jbpm.jpdl.xml.ProblemListener;
import org.jbpm.scheduler.def.CancelTimerAction;
import org.jbpm.scheduler.def.CreateTimerAction;
import org.jbpm.taskmgmt.def.Task;
import org.xml.sax.InputSource;
/**
* Extended JpdlXmlReader with access to problems encountered during compile.
*
* Provides extension to Timers (to allow for absolute date).
*
* @author davidc
*/
public class JBPMJpdlXmlReader extends JpdlXmlReader
{
private static final long serialVersionUID = -753730152120696221L;
/*
* Construct
*/
public JBPMJpdlXmlReader(InputStream inputStream)
{
super(new InputSource(inputStream));
}
/*
* Construct
*/
public JBPMJpdlXmlReader(InputSource inputSource, ProblemListener problemListener)
{
super(inputSource, problemListener);
}
/*
* Construct
*/
public JBPMJpdlXmlReader(InputSource inputSource)
{
super(inputSource);
}
/*
* Construct
*/
public JBPMJpdlXmlReader(Reader reader)
{
super(reader);
}
/**
* {@inheritDoc}
*/
@Override
protected void readNodeTimer(Element timerElement, Node node)
{
// NOTE: This method implementation is a copy from the JpdlXmlReader class
// with the difference of constructing an AlfrescoCreateTimerAction.
// It may need to be updated whenever a jbpm library upgrade is performed.
String name = timerElement.attributeValue("name", node.getName());
CreateTimerAction createTimerAction = new AlfrescoCreateTimerAction();
createTimerAction.read(timerElement, this);
createTimerAction.setTimerName(name);
createTimerAction.setTimerAction(readSingleAction(timerElement));
addAction(node, Event.EVENTTYPE_NODE_ENTER, createTimerAction);
CancelTimerAction cancelTimerAction = new CancelTimerAction();
cancelTimerAction.setTimerName(name);
addAction(node, Event.EVENTTYPE_NODE_LEAVE, cancelTimerAction);
}
/**
* {@inheritDoc}
*/
@Override
protected void readTaskTimer(Element timerElement, Task task)
{
// NOTE: This method implementation is a copy from the JpdlXmlReader class
// with the difference of constructing an AlfrescoCreateTimerAction.
// It may need to be updated whenever a jbpm library upgrade is performed.
String name = timerElement.attributeValue("name", task.getName());
if (name == null)
name = "timer-for-task-" + task.getId();
CreateTimerAction createTimerAction = new AlfrescoCreateTimerAction();
createTimerAction.read(timerElement, this);
createTimerAction.setTimerName(name);
Action action = null;
if ("timer".equals(timerElement.getName()))
{
action = readSingleAction(timerElement);
}
else
{
Delegation delegation = createMailDelegation("task-reminder", null, null, null, null);
action = new Action(delegation);
}
createTimerAction.setTimerAction(action);
addAction(task, Event.EVENTTYPE_TASK_CREATE, createTimerAction);
// read the cancel-event types
Collection<String> cancelEventTypes = new ArrayList<String>();
String cancelEventTypeText = timerElement.attributeValue("cancel-event");
if (cancelEventTypeText != null)
{
// cancel-event is a comma separated list of events
StringTokenizer tokenizer = new StringTokenizer(cancelEventTypeText, ",");
while (tokenizer.hasMoreTokens())
{
cancelEventTypes.add(tokenizer.nextToken().trim());
}
}
else
{
// set the default
cancelEventTypes.add(Event.EVENTTYPE_TASK_END);
}
for (String cancelEventType : cancelEventTypes)
{
CancelTimerAction cancelTimerAction = new CancelTimerAction();
cancelTimerAction.setTimerName(name);
addAction(task, cancelEventType, cancelTimerAction);
}
}
/**
* Gets the problems
*
* @return problems
*/
@SuppressWarnings("unchecked")
public List<Problem> getProblems()
{
return problems;
}
}
package org.alfresco.repo.workflow.jbpm;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;
import org.dom4j.Element;
import org.jbpm.graph.def.Action;
import org.jbpm.graph.def.Event;
import org.jbpm.graph.def.Node;
import org.jbpm.instantiation.Delegation;
import org.jbpm.jpdl.xml.JpdlXmlReader;
import org.jbpm.jpdl.xml.Problem;
import org.jbpm.jpdl.xml.ProblemListener;
import org.jbpm.scheduler.def.CancelTimerAction;
import org.jbpm.scheduler.def.CreateTimerAction;
import org.jbpm.taskmgmt.def.Task;
import org.xml.sax.InputSource;
/**
* Extended JpdlXmlReader with access to problems encountered during compile.
*
* Provides extension to Timers (to allow for absolute date).
*
* @author davidc
*/
public class JBPMJpdlXmlReader extends JpdlXmlReader
{
private static final long serialVersionUID = -753730152120696221L;
/*
* Construct
*/
public JBPMJpdlXmlReader(InputStream inputStream)
{
super(new InputSource(inputStream));
}
/*
* Construct
*/
public JBPMJpdlXmlReader(InputSource inputSource, ProblemListener problemListener)
{
super(inputSource, problemListener);
}
/*
* Construct
*/
public JBPMJpdlXmlReader(InputSource inputSource)
{
super(inputSource);
}
/*
* Construct
*/
public JBPMJpdlXmlReader(Reader reader)
{
super(reader);
}
/**
* {@inheritDoc}
*/
@Override
protected void readNodeTimer(Element timerElement, Node node)
{
// NOTE: This method implementation is a copy from the JpdlXmlReader class
// with the difference of constructing an AlfrescoCreateTimerAction.
// It may need to be updated whenever a jbpm library upgrade is performed.
String name = timerElement.attributeValue("name", node.getName());
CreateTimerAction createTimerAction = new AlfrescoCreateTimerAction();
createTimerAction.read(timerElement, this);
createTimerAction.setTimerName(name);
createTimerAction.setTimerAction(readSingleAction(timerElement));
addAction(node, Event.EVENTTYPE_NODE_ENTER, createTimerAction);
CancelTimerAction cancelTimerAction = new CancelTimerAction();
cancelTimerAction.setTimerName(name);
addAction(node, Event.EVENTTYPE_NODE_LEAVE, cancelTimerAction);
}
/**
* {@inheritDoc}
*/
@Override
protected void readTaskTimer(Element timerElement, Task task)
{
// NOTE: This method implementation is a copy from the JpdlXmlReader class
// with the difference of constructing an AlfrescoCreateTimerAction.
// It may need to be updated whenever a jbpm library upgrade is performed.
String name = timerElement.attributeValue("name", task.getName());
if (name == null)
name = "timer-for-task-" + task.getId();
CreateTimerAction createTimerAction = new AlfrescoCreateTimerAction();
createTimerAction.read(timerElement, this);
createTimerAction.setTimerName(name);
Action action = null;
if ("timer".equals(timerElement.getName()))
{
action = readSingleAction(timerElement);
}
else
{
Delegation delegation = createMailDelegation("task-reminder", null, null, null, null);
action = new Action(delegation);
}
createTimerAction.setTimerAction(action);
addAction(task, Event.EVENTTYPE_TASK_CREATE, createTimerAction);
// read the cancel-event types
Collection<String> cancelEventTypes = new ArrayList<String>();
String cancelEventTypeText = timerElement.attributeValue("cancel-event");
if (cancelEventTypeText != null)
{
// cancel-event is a comma separated list of events
StringTokenizer tokenizer = new StringTokenizer(cancelEventTypeText, ",");
while (tokenizer.hasMoreTokens())
{
cancelEventTypes.add(tokenizer.nextToken().trim());
}
}
else
{
// set the default
cancelEventTypes.add(Event.EVENTTYPE_TASK_END);
}
for (String cancelEventType : cancelEventTypes)
{
CancelTimerAction cancelTimerAction = new CancelTimerAction();
cancelTimerAction.setTimerName(name);
addAction(task, cancelEventType, cancelTimerAction);
}
}
/**
* Gets the problems
*
* @return problems
*/
@SuppressWarnings("unchecked")
public List<Problem> getProblems()
{
return problems;
}
}

View File

@@ -1,82 +1,82 @@
package org.alfresco.repo.workflow.jbpm;
import java.io.Serializable;
import java.util.Date;
import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.mozilla.javascript.Context;
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 ScriptNode
{
private static final long serialVersionUID = -826970280203254365L;
/**
* Construct
*
* @param nodeRef node reference
* @param services services
*/
public JBPMNode(NodeRef nodeRef, ServiceRegistry services)
{
super(nodeRef, services, NullScope.instance());
}
/**
* {@inheritDoc}
*/
@Override
protected NodeValueConverter createValueConverter()
{
return new JBPMNodeConverter();
}
/**
* Value converter for beanshell.
*/
private class JBPMNodeConverter extends NodeValueConverter
{
@Override
public Serializable convertValueForRepo(Serializable value)
{
if (value instanceof Date)
{
return value;
}
else
{
return super.convertValueForRepo(value);
}
}
@Override
public Serializable convertValueForScript(ServiceRegistry serviceRegistry, Scriptable theScope, QName qname, Serializable value)
{
if (value instanceof NodeRef)
{
return new JBPMNode(((NodeRef)value), serviceRegistry);
}
else if (value instanceof Date)
{
return value;
}
else
{
return super.convertValueForScript(serviceRegistry, theScope, qname, value);
}
}
}
}
package org.alfresco.repo.workflow.jbpm;
import java.io.Serializable;
import java.util.Date;
import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.mozilla.javascript.Context;
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 ScriptNode
{
private static final long serialVersionUID = -826970280203254365L;
/**
* Construct
*
* @param nodeRef node reference
* @param services services
*/
public JBPMNode(NodeRef nodeRef, ServiceRegistry services)
{
super(nodeRef, services, NullScope.instance());
}
/**
* {@inheritDoc}
*/
@Override
protected NodeValueConverter createValueConverter()
{
return new JBPMNodeConverter();
}
/**
* Value converter for beanshell.
*/
private class JBPMNodeConverter extends NodeValueConverter
{
@Override
public Serializable convertValueForRepo(Serializable value)
{
if (value instanceof Date)
{
return value;
}
else
{
return super.convertValueForRepo(value);
}
}
@Override
public Serializable convertValueForScript(ServiceRegistry serviceRegistry, Scriptable theScope, QName qname, Serializable value)
{
if (value instanceof NodeRef)
{
return new JBPMNode(((NodeRef)value), serviceRegistry);
}
else if (value instanceof Date)
{
return value;
}
else
{
return super.convertValueForScript(serviceRegistry, theScope, qname, value);
}
}
}
}

View File

@@ -1,15 +1,15 @@
package org.alfresco.repo.workflow.jbpm;
import java.util.ArrayList;
/**
* List of jBPM Nodes
*
* @author davidc
*/
public class JBPMNodeList extends ArrayList<JBPMNode>
{
private static final long serialVersionUID = 1376915749912156471L;
}
package org.alfresco.repo.workflow.jbpm;
import java.util.ArrayList;
/**
* List of jBPM Nodes
*
* @author davidc
*/
public class JBPMNodeList extends ArrayList<JBPMNode>
{
private static final long serialVersionUID = 1376915749912156471L;
}

View File

@@ -1,57 +1,57 @@
package org.alfresco.repo.workflow.jbpm;
import org.jbpm.job.executor.JobExecutor;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springmodules.workflow.jbpm31.JbpmTemplate;
/**
* JBPM Scheduler
*
* Manages lifecycle of Jbpm Job Executor.
*
* @author davidc
*/
public class JBPMScheduler extends AbstractLifecycleBean
{
private JobExecutor executor = null;
private JbpmTemplate jbpmTemplate;
private boolean JbpmEngineEnabled = false;
/**
* @param jbpmTemplate JbpmTemplate
*/
public void setJBPMTemplate(JbpmTemplate jbpmTemplate)
{
this.jbpmTemplate = jbpmTemplate;
}
/**
* @param jbpmEngineEnabled whether or not the JBPM-Engine is enables. Please note that we are
* not using the WorklfowAdminService since this is only initialized later in the sequence.
*/
public void setJBPMEngineEnabled(boolean jbpmEngineEnabled) {
JbpmEngineEnabled = jbpmEngineEnabled;
}
@Override
protected void onBootstrap(ApplicationEvent event)
{
if(JbpmEngineEnabled)
{
executor = jbpmTemplate.getJbpmConfiguration().getJobExecutor();
executor.start();
}
}
@Override
protected void onShutdown(ApplicationEvent event)
{
if(JbpmEngineEnabled && executor.isStarted())
{
executor.stop();
}
}
}
package org.alfresco.repo.workflow.jbpm;
import org.jbpm.job.executor.JobExecutor;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springmodules.workflow.jbpm31.JbpmTemplate;
/**
* JBPM Scheduler
*
* Manages lifecycle of Jbpm Job Executor.
*
* @author davidc
*/
public class JBPMScheduler extends AbstractLifecycleBean
{
private JobExecutor executor = null;
private JbpmTemplate jbpmTemplate;
private boolean JbpmEngineEnabled = false;
/**
* @param jbpmTemplate JbpmTemplate
*/
public void setJBPMTemplate(JbpmTemplate jbpmTemplate)
{
this.jbpmTemplate = jbpmTemplate;
}
/**
* @param jbpmEngineEnabled whether or not the JBPM-Engine is enables. Please note that we are
* not using the WorklfowAdminService since this is only initialized later in the sequence.
*/
public void setJBPMEngineEnabled(boolean jbpmEngineEnabled) {
JbpmEngineEnabled = jbpmEngineEnabled;
}
@Override
protected void onBootstrap(ApplicationEvent event)
{
if(JbpmEngineEnabled)
{
executor = jbpmTemplate.getJbpmConfiguration().getJobExecutor();
executor.start();
}
}
@Override
protected void onShutdown(ApplicationEvent event)
{
if(JbpmEngineEnabled && executor.isStarted())
{
executor.stop();
}
}
}

View File

@@ -1,53 +1,53 @@
package org.alfresco.repo.workflow.jbpm;
import org.alfresco.repo.workflow.BPMEngineRegistry;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
/**
* Abstract base implementation of a Jbpm Action Hander with access to
* Alfresco Spring beans.
*
* @author davidc
*/
public abstract class JBPMSpringActionHandler implements ActionHandler
{
private static final long serialVersionUID = 6848343645482681529L;
/**
* Construct
*/
protected JBPMSpringActionHandler()
{
// The following implementation is derived from Spring Modules v0.4
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
initialiseHandler(factory.getFactory());
}
/**
* Initialise Action Handler
*
* @param factory Spring bean factory for accessing Alfresco beans
*/
protected abstract void initialiseHandler(BeanFactory factory);
/**
* Gets the workflow instance id of the currently executing workflow
*
* @param context jBPM execution context
* @return workflow instance id
*/
protected String getWorkflowInstanceId(ExecutionContext context)
{
String id = new Long(context.getProcessInstance().getId()).toString();
return BPMEngineRegistry.createGlobalId(JBPMEngine.ENGINE_ID, id);
}
}
package org.alfresco.repo.workflow.jbpm;
import org.alfresco.repo.workflow.BPMEngineRegistry;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
/**
* Abstract base implementation of a Jbpm Action Hander with access to
* Alfresco Spring beans.
*
* @author davidc
*/
public abstract class JBPMSpringActionHandler implements ActionHandler
{
private static final long serialVersionUID = 6848343645482681529L;
/**
* Construct
*/
protected JBPMSpringActionHandler()
{
// The following implementation is derived from Spring Modules v0.4
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
initialiseHandler(factory.getFactory());
}
/**
* Initialise Action Handler
*
* @param factory Spring bean factory for accessing Alfresco beans
*/
protected abstract void initialiseHandler(BeanFactory factory);
/**
* Gets the workflow instance id of the currently executing workflow
*
* @param context jBPM execution context
* @return workflow instance id
*/
protected String getWorkflowInstanceId(ExecutionContext context)
{
String id = new Long(context.getProcessInstance().getId()).toString();
return BPMEngineRegistry.createGlobalId(JBPMEngine.ENGINE_ID, id);
}
}

View File

@@ -1,39 +1,39 @@
package org.alfresco.repo.workflow.jbpm;
import org.jbpm.taskmgmt.def.AssignmentHandler;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
/**
* Abstract base implementation of a Jbpm Assignment Handler with access to
* Alfresco Spring beans.
*
* @author davidc
*/
public abstract class JBPMSpringAssignmentHandler implements AssignmentHandler
{
private static final long serialVersionUID = -2233750219905283562L;
/**
* Construct
*/
protected JBPMSpringAssignmentHandler()
{
// The following implementation is derived from Spring Modules v0.4
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
initialiseHandler(factory.getFactory());
}
/**
* Initialise Action Handler
*
* @param factory Spring bean factory for accessing Alfresco beans
*/
protected abstract void initialiseHandler(BeanFactory factory);
}
package org.alfresco.repo.workflow.jbpm;
import org.jbpm.taskmgmt.def.AssignmentHandler;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springmodules.workflow.jbpm31.JbpmFactoryLocator;
/**
* Abstract base implementation of a Jbpm Assignment Handler with access to
* Alfresco Spring beans.
*
* @author davidc
*/
public abstract class JBPMSpringAssignmentHandler implements AssignmentHandler
{
private static final long serialVersionUID = -2233750219905283562L;
/**
* Construct
*/
protected JBPMSpringAssignmentHandler()
{
// The following implementation is derived from Spring Modules v0.4
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
initialiseHandler(factory.getFactory());
}
/**
* Initialise Action Handler
*
* @param factory Spring bean factory for accessing Alfresco beans
*/
protected abstract void initialiseHandler(BeanFactory factory);
}

View File

@@ -1,47 +1,47 @@
package org.alfresco.repo.workflow.jbpm;
import org.alfresco.service.descriptor.DescriptorService;
import org.jbpm.graph.exe.ExecutionContext;
import org.springframework.beans.factory.BeanFactory;
/**
* Test Spring based Jbpm Action Handler
*
* @author davidc
*/
public class JBPMTestSpringActionHandler extends JBPMSpringActionHandler
{
private static final long serialVersionUID = -7659883022289711381L;
private DescriptorService descriptorService;
private String value;
/**
* Setter accessible from jBPM jPDL
* @param value String
*/
public void setValue(String value)
{
this.value = value;
}
/*
* (non-Javadoc)
* @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
*/
public void execute(ExecutionContext arg0) throws Exception
{
String result = "Repo: " + descriptorService.getServerDescriptor().getVersion();
result += ", Value: " + value + ", Node: " + arg0.getNode().getName() + ", Token: " + arg0.getToken().getFullName();
arg0.getContextInstance().setVariable("jbpm.test.action.result", result);
}
@Override
protected void initialiseHandler(BeanFactory factory)
{
descriptorService = factory.getBean("DescriptorService", DescriptorService.class);
}
}
package org.alfresco.repo.workflow.jbpm;
import org.alfresco.service.descriptor.DescriptorService;
import org.jbpm.graph.exe.ExecutionContext;
import org.springframework.beans.factory.BeanFactory;
/**
* Test Spring based Jbpm Action Handler
*
* @author davidc
*/
public class JBPMTestSpringActionHandler extends JBPMSpringActionHandler
{
private static final long serialVersionUID = -7659883022289711381L;
private DescriptorService descriptorService;
private String value;
/**
* Setter accessible from jBPM jPDL
* @param value String
*/
public void setValue(String value)
{
this.value = value;
}
/*
* (non-Javadoc)
* @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
*/
public void execute(ExecutionContext arg0) throws Exception
{
String result = "Repo: " + descriptorService.getServerDescriptor().getVersion();
result += ", Value: " + value + ", Node: " + arg0.getNode().getName() + ", Token: " + arg0.getToken().getFullName();
arg0.getContextInstance().setVariable("jbpm.test.action.result", result);
}
@Override
protected void initialiseHandler(BeanFactory factory)
{
descriptorService = factory.getBean("DescriptorService", DescriptorService.class);
}
}

View File

@@ -1,211 +1,211 @@
package org.alfresco.repo.workflow.jbpm;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionListener;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.springmodules.workflow.jbpm31.JbpmTemplate;
/**
* JBPM Template that manages JBPM Context at the Alfresco Transaction level
*
* @author davidc
*/
public class JBPMTransactionTemplate extends JbpmTemplate
implements TransactionListener
{
// Logging support
private static Log logger = LogFactory.getLog("org.alfresco.repo.workflow");
/** Id used in equals and hash */
private String id = GUID.generate();
// JBPM Template Keys
private static final String JBPM_CONTEXT_KEY = JBPMTransactionTemplate.class.getName() + ".context";
/** Use local or transaction bound JBPM Context */
private boolean localContext = true;
/*
* Constructor
*/
public JBPMTransactionTemplate()
{
super();
}
/*
* Constructor
*/
public JBPMTransactionTemplate(JbpmConfiguration jbpmConfiguration, ProcessDefinition processDefinition)
{
super(jbpmConfiguration, processDefinition);
}
/*
* Constructor
*/
public JBPMTransactionTemplate(JbpmConfiguration jbpmConfiguration)
{
super(jbpmConfiguration);
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("synthetic-access")
@Override
public void afterPropertiesSet() throws Exception
{
try
{
JBPMTransactionTemplate.super.afterPropertiesSet();
}
finally
{
localContext = false;
}
}
/**
* {@inheritDoc}
*/
@Override
protected JbpmContext getContext()
{
if (localContext)
{
return super.getContext();
}
else
{
JbpmContext context = (JbpmContext)AlfrescoTransactionSupport.getResource(JBPM_CONTEXT_KEY);
if (context == null)
{
context = super.getContext();
AlfrescoTransactionSupport.bindResource(JBPM_CONTEXT_KEY, context);
AlfrescoTransactionSupport.bindListener(this);
if (logger.isDebugEnabled())
logger.debug("Attached JBPM Context to transaction " + AlfrescoTransactionSupport.getTransactionId());
}
return context;
}
}
/**
* {@inheritDoc}
*/
@Override
protected void releaseContext(JbpmContext jbpmContext)
{
if (localContext)
{
jbpmContext.close();
}
else
{
// NOTE: Defer release to end of transaction
}
}
/**
* {@inheritDoc}
*/
public void flush()
{
//NOOP
}
/**
* {@inheritDoc}
*/
public void beforeCommit(boolean readOnly)
{
//NOOP
}
/**
* {@inheritDoc}
*/
public void beforeCompletion()
{
//NOOP
}
/**
* {@inheritDoc}
*/
public void afterCommit()
{
JbpmContext context = (JbpmContext)AlfrescoTransactionSupport.getResource(JBPM_CONTEXT_KEY);
if (context != null)
{
super.releaseContext(context);
if (logger.isDebugEnabled())
logger.debug("Detached (commit) JBPM Context from transaction " + AlfrescoTransactionSupport.getTransactionId());
}
}
/**
* {@inheritDoc}
*/
public void afterRollback()
{
JbpmContext context = (JbpmContext)AlfrescoTransactionSupport.getResource(JBPM_CONTEXT_KEY);
if (context != null)
{
super.releaseContext(context);
if (logger.isDebugEnabled())
logger.debug("Detached (rollback) JBPM Context from transaction " + AlfrescoTransactionSupport.getTransactionId());
}
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
return this.id.hashCode();
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj instanceof JBPMTransactionTemplate)
{
JBPMTransactionTemplate that = (JBPMTransactionTemplate) obj;
return (this.id.equals(that.id));
}
else
{
return false;
}
}
}
package org.alfresco.repo.workflow.jbpm;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionListener;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.springmodules.workflow.jbpm31.JbpmTemplate;
/**
* JBPM Template that manages JBPM Context at the Alfresco Transaction level
*
* @author davidc
*/
public class JBPMTransactionTemplate extends JbpmTemplate
implements TransactionListener
{
// Logging support
private static Log logger = LogFactory.getLog("org.alfresco.repo.workflow");
/** Id used in equals and hash */
private String id = GUID.generate();
// JBPM Template Keys
private static final String JBPM_CONTEXT_KEY = JBPMTransactionTemplate.class.getName() + ".context";
/** Use local or transaction bound JBPM Context */
private boolean localContext = true;
/*
* Constructor
*/
public JBPMTransactionTemplate()
{
super();
}
/*
* Constructor
*/
public JBPMTransactionTemplate(JbpmConfiguration jbpmConfiguration, ProcessDefinition processDefinition)
{
super(jbpmConfiguration, processDefinition);
}
/*
* Constructor
*/
public JBPMTransactionTemplate(JbpmConfiguration jbpmConfiguration)
{
super(jbpmConfiguration);
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("synthetic-access")
@Override
public void afterPropertiesSet() throws Exception
{
try
{
JBPMTransactionTemplate.super.afterPropertiesSet();
}
finally
{
localContext = false;
}
}
/**
* {@inheritDoc}
*/
@Override
protected JbpmContext getContext()
{
if (localContext)
{
return super.getContext();
}
else
{
JbpmContext context = (JbpmContext)AlfrescoTransactionSupport.getResource(JBPM_CONTEXT_KEY);
if (context == null)
{
context = super.getContext();
AlfrescoTransactionSupport.bindResource(JBPM_CONTEXT_KEY, context);
AlfrescoTransactionSupport.bindListener(this);
if (logger.isDebugEnabled())
logger.debug("Attached JBPM Context to transaction " + AlfrescoTransactionSupport.getTransactionId());
}
return context;
}
}
/**
* {@inheritDoc}
*/
@Override
protected void releaseContext(JbpmContext jbpmContext)
{
if (localContext)
{
jbpmContext.close();
}
else
{
// NOTE: Defer release to end of transaction
}
}
/**
* {@inheritDoc}
*/
public void flush()
{
//NOOP
}
/**
* {@inheritDoc}
*/
public void beforeCommit(boolean readOnly)
{
//NOOP
}
/**
* {@inheritDoc}
*/
public void beforeCompletion()
{
//NOOP
}
/**
* {@inheritDoc}
*/
public void afterCommit()
{
JbpmContext context = (JbpmContext)AlfrescoTransactionSupport.getResource(JBPM_CONTEXT_KEY);
if (context != null)
{
super.releaseContext(context);
if (logger.isDebugEnabled())
logger.debug("Detached (commit) JBPM Context from transaction " + AlfrescoTransactionSupport.getTransactionId());
}
}
/**
* {@inheritDoc}
*/
public void afterRollback()
{
JbpmContext context = (JbpmContext)AlfrescoTransactionSupport.getResource(JBPM_CONTEXT_KEY);
if (context != null)
{
super.releaseContext(context);
if (logger.isDebugEnabled())
logger.debug("Detached (rollback) JBPM Context from transaction " + AlfrescoTransactionSupport.getTransactionId());
}
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
return this.id.hashCode();
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj instanceof JBPMTransactionTemplate)
{
JBPMTransactionTemplate that = (JBPMTransactionTemplate) obj;
return (this.id.equals(that.id));
}
else
{
return false;
}
}
}

View File

@@ -1,50 +1,50 @@
package org.alfresco.repo.workflow.jbpm;
import org.dom4j.Element;
import org.jbpm.graph.def.Action;
import org.jbpm.graph.def.Event;
import org.jbpm.instantiation.Delegation;
import org.jbpm.jpdl.xml.JpdlXmlReader;
/**
* Implementation of Join which ends child tokens / tasks for nOutM cases.
*
* @author davidc
*
*/
public class Join extends org.jbpm.graph.node.Join
{
private static final long serialVersionUID = 6417483503439714897L;
/**
* Constructor
*/
public Join()
{
super();
}
/**
* Constructor
*/
public Join(String name)
{
super(name);
}
/**
* {@inheritDoc}
*/
@Override
public void read(Element element, JpdlXmlReader jpdlReader)
{
// Add "on node leave" event handler which ends child tokens / tasks
Delegation delegation = new Delegation(JoinEndForkedTokens.class.getName());
Action theAction = new Action(delegation);
Event event = new Event(Event.EVENTTYPE_NODE_LEAVE);
event.addAction(theAction);
addEvent(event);
}
}
package org.alfresco.repo.workflow.jbpm;
import org.dom4j.Element;
import org.jbpm.graph.def.Action;
import org.jbpm.graph.def.Event;
import org.jbpm.instantiation.Delegation;
import org.jbpm.jpdl.xml.JpdlXmlReader;
/**
* Implementation of Join which ends child tokens / tasks for nOutM cases.
*
* @author davidc
*
*/
public class Join extends org.jbpm.graph.node.Join
{
private static final long serialVersionUID = 6417483503439714897L;
/**
* Constructor
*/
public Join()
{
super();
}
/**
* Constructor
*/
public Join(String name)
{
super(name);
}
/**
* {@inheritDoc}
*/
@Override
public void read(Element element, JpdlXmlReader jpdlReader)
{
// Add "on node leave" event handler which ends child tokens / tasks
Delegation delegation = new Delegation(JoinEndForkedTokens.class.getName());
Action theAction = new Action(delegation);
Event event = new Event(Event.EVENTTYPE_NODE_LEAVE);
event.addAction(theAction);
addEvent(event);
}
}

View File

@@ -1,94 +1,94 @@
package org.alfresco.repo.workflow.jbpm;
import java.util.Collection;
import java.util.Map;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;
import org.jbpm.taskmgmt.exe.TaskInstance;
import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
/**
* Action Handler for ending child tokens / tasks
*
* @author davidc
*/
public class JoinEndForkedTokens implements ActionHandler
{
private static final long serialVersionUID = 8679390550752208189L;
/**
* Constructor
*/
public JoinEndForkedTokens()
{
super();
}
/**
* {@inheritDoc}
*/
public void execute(ExecutionContext executionContext)
{
Token token = executionContext.getToken();
Map<?, ?> childTokens = token.getActiveChildren();
for (Object childToken : childTokens.values())
{
cancelToken(executionContext, (Token)childToken);
}
}
/**
* Cancel token
*
* @param executionContext ExecutionContext
* @param token Token
*/
protected void cancelToken(ExecutionContext executionContext, Token token)
{
// visit child tokens
Map<?, ?> childTokens = token.getActiveChildren();
for (Object childToken : childTokens.values())
{
cancelToken(executionContext, (Token)childToken);
}
// end token
if (!token.hasEnded())
{
token.end(false);
}
// end any associated tasks
cancelTokenTasks(executionContext, token);
}
/**
* Cancel tasks associated with a token
*
* @param executionContext ExecutionContext
* @param token Token
*/
protected void cancelTokenTasks(ExecutionContext executionContext, Token token)
{
TaskMgmtInstance tms = executionContext.getTaskMgmtInstance();
Collection<TaskInstance> tasks = tms.getUnfinishedTasks(token);
for (Object task : tasks)
{
TaskInstance taskInstance = (TaskInstance)task;
if (taskInstance.isBlocking())
{
taskInstance.setBlocking(false);
}
if (taskInstance.isSignalling())
{
taskInstance.setSignalling(false);
}
if (!taskInstance.hasEnded())
{
taskInstance.cancel();
}
}
}
}
package org.alfresco.repo.workflow.jbpm;
import java.util.Collection;
import java.util.Map;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.Token;
import org.jbpm.taskmgmt.exe.TaskInstance;
import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
/**
* Action Handler for ending child tokens / tasks
*
* @author davidc
*/
public class JoinEndForkedTokens implements ActionHandler
{
private static final long serialVersionUID = 8679390550752208189L;
/**
* Constructor
*/
public JoinEndForkedTokens()
{
super();
}
/**
* {@inheritDoc}
*/
public void execute(ExecutionContext executionContext)
{
Token token = executionContext.getToken();
Map<?, ?> childTokens = token.getActiveChildren();
for (Object childToken : childTokens.values())
{
cancelToken(executionContext, (Token)childToken);
}
}
/**
* Cancel token
*
* @param executionContext ExecutionContext
* @param token Token
*/
protected void cancelToken(ExecutionContext executionContext, Token token)
{
// visit child tokens
Map<?, ?> childTokens = token.getActiveChildren();
for (Object childToken : childTokens.values())
{
cancelToken(executionContext, (Token)childToken);
}
// end token
if (!token.hasEnded())
{
token.end(false);
}
// end any associated tasks
cancelTokenTasks(executionContext, token);
}
/**
* Cancel tasks associated with a token
*
* @param executionContext ExecutionContext
* @param token Token
*/
protected void cancelTokenTasks(ExecutionContext executionContext, Token token)
{
TaskMgmtInstance tms = executionContext.getTaskMgmtInstance();
Collection<TaskInstance> tasks = tms.getUnfinishedTasks(token);
for (Object task : tasks)
{
TaskInstance taskInstance = (TaskInstance)task;
if (taskInstance.isBlocking())
{
taskInstance.setBlocking(false);
}
if (taskInstance.isSignalling())
{
taskInstance.setSignalling(false);
}
if (!taskInstance.hasEnded())
{
taskInstance.cancel();
}
}
}
}

View File

@@ -1,63 +1,63 @@
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;
}
}
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;
}
}

View File

@@ -1,110 +1,110 @@
package org.alfresco.repo.workflow.jbpm;
import java.util.ArrayList;
import java.util.Collection;
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.jbpm.graph.def.ProcessDefinition;
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
* @author Nick Smith
*/
public class NodeListConverter extends SerializableToByteArrayConverter
{
private static final long serialVersionUID = 1L;
private static BeanFactoryLocator jbpmFactoryLocator = new JbpmFactoryLocator();
/**
* {@inheritDoc}
*/
@Override
public boolean supports(Object value)
{
if (value == null)
{
return true;
}
return (value.getClass() == JBPMNodeList.class);
}
/**
* {@inheritDoc}
*/
@Override
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;
}
/**
* {@inheritDoc}
*/
@Override
public Object revert(Object o)
{
Object reverted = null;
if (o != null)
{
Object nodeRefs = super.revert(o);
reverted = revertNodes(nodeRefs);
}
return reverted;
}
/**
* {@inheritDoc}
*/
@Override
public Object revert(Object o, ProcessDefinition processDefinition)
{
Object reverted = null;
if (o != null)
{
Object nodeRefs = super.revert(o, processDefinition);
reverted = revertNodes(nodeRefs);
}
return reverted;
}
/**
* @param value Object
* @return JBPMNodeList
*/
@SuppressWarnings("unchecked")
private JBPMNodeList revertNodes(Object value)
{
BeanFactoryReference factory = jbpmFactoryLocator.useBeanFactory(null);
ServiceRegistry serviceRegistry = (ServiceRegistry)factory.getFactory().getBean(ServiceRegistry.SERVICE_REGISTRY);
JBPMNodeList nodes = new JBPMNodeList();
Collection<NodeRef> nodeRefs = (Collection<NodeRef>) value;
for (NodeRef nodeRef : nodeRefs)
{
nodes.add(new JBPMNode(nodeRef, serviceRegistry));
}
return nodes;
}
}
package org.alfresco.repo.workflow.jbpm;
import java.util.ArrayList;
import java.util.Collection;
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.jbpm.graph.def.ProcessDefinition;
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
* @author Nick Smith
*/
public class NodeListConverter extends SerializableToByteArrayConverter
{
private static final long serialVersionUID = 1L;
private static BeanFactoryLocator jbpmFactoryLocator = new JbpmFactoryLocator();
/**
* {@inheritDoc}
*/
@Override
public boolean supports(Object value)
{
if (value == null)
{
return true;
}
return (value.getClass() == JBPMNodeList.class);
}
/**
* {@inheritDoc}
*/
@Override
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;
}
/**
* {@inheritDoc}
*/
@Override
public Object revert(Object o)
{
Object reverted = null;
if (o != null)
{
Object nodeRefs = super.revert(o);
reverted = revertNodes(nodeRefs);
}
return reverted;
}
/**
* {@inheritDoc}
*/
@Override
public Object revert(Object o, ProcessDefinition processDefinition)
{
Object reverted = null;
if (o != null)
{
Object nodeRefs = super.revert(o, processDefinition);
reverted = revertNodes(nodeRefs);
}
return reverted;
}
/**
* @param value Object
* @return JBPMNodeList
*/
@SuppressWarnings("unchecked")
private JBPMNodeList revertNodes(Object value)
{
BeanFactoryReference factory = jbpmFactoryLocator.useBeanFactory(null);
ServiceRegistry serviceRegistry = (ServiceRegistry)factory.getFactory().getBean(ServiceRegistry.SERVICE_REGISTRY);
JBPMNodeList nodes = new JBPMNodeList();
Collection<NodeRef> nodeRefs = (Collection<NodeRef>) value;
for (NodeRef nodeRef : nodeRefs)
{
nodes.add(new JBPMNode(nodeRef, serviceRegistry));
}
return nodes;
}
}

View File

@@ -1,131 +1,131 @@
package org.alfresco.repo.workflow.jbpm;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.namespace.QName;
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;
/**
* Used to look up the Alfresco JBPM Engine.
*/
private String jbpmEngineName = null;
/** Alfresco JBPM Engine */
private static JBPMEngine jbpmEngine = null;
/**
* Construct
*/
public WorkflowTaskInstance()
{
super();
}
/**
* Construct
*
* @param taskName String
* @param actorId String
*/
public WorkflowTaskInstance(String taskName, String actorId)
{
super(taskName, actorId);
}
/**
* Sets jbpmEngineName which is used to get the JBPMEngine instance from a
* BeanFactory
*
* @param jbpmEngineName the jbpmEngineName to set
*/
public void setJbpmEngineName(String jbpmEngineName)
{
this.jbpmEngineName = jbpmEngineName;
}
/**
* Gets the JBPM Engine instance
*
* @return JBPM Engine
*/
private JBPMEngine getJBPMEngine()
{
if (jbpmEngine == null)
{
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
if (jbpmEngineName == null) jbpmEngineName = "jbpm_engine";
jbpmEngine = (JBPMEngine) factory.getFactory().getBean(jbpmEngineName);
if (jbpmEngine == null) { throw new WorkflowException(
"Failed to retrieve JBPMEngine component"); }
}
return jbpmEngine;
}
@Override
public void create(ExecutionContext executionContext)
{
super.create(executionContext);
getJBPMEngine().setDefaultTaskProperties(this);
}
@Override
public void end(Transition transition)
{
// Force assignment of task if transition is taken, but no owner has yet
// been assigned
if (actorId == null)
{
actorId = AuthenticationUtil.getFullyAuthenticatedUser();
}
// Set task properties on completion of task
// NOTE: Set properties first, so they're available during the
// submission of
// task variables to the process context
Map<QName, Serializable> taskProperties = new HashMap<QName, Serializable>();
Transition outcome = (transition == null) ? token.getNode().getDefaultLeavingTransition()
: transition;
if (outcome != null)
{
taskProperties.put(WorkflowModel.PROP_OUTCOME, outcome.getName());
}
taskProperties.put(WorkflowModel.PROP_STATUS, "Completed");
getJBPMEngine().setTaskProperties(this, taskProperties);
// perform transition
super.end(transition);
if (getTask().getStartState() != null)
{
// if ending a start task, push start task properties to process
// context, if not
// already done
getJBPMEngine().setDefaultWorkflowProperties(this);
// set task description
getJBPMEngine().setDefaultStartTaskDescription(this);
}
}
}
package org.alfresco.repo.workflow.jbpm;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.namespace.QName;
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;
/**
* Used to look up the Alfresco JBPM Engine.
*/
private String jbpmEngineName = null;
/** Alfresco JBPM Engine */
private static JBPMEngine jbpmEngine = null;
/**
* Construct
*/
public WorkflowTaskInstance()
{
super();
}
/**
* Construct
*
* @param taskName String
* @param actorId String
*/
public WorkflowTaskInstance(String taskName, String actorId)
{
super(taskName, actorId);
}
/**
* Sets jbpmEngineName which is used to get the JBPMEngine instance from a
* BeanFactory
*
* @param jbpmEngineName the jbpmEngineName to set
*/
public void setJbpmEngineName(String jbpmEngineName)
{
this.jbpmEngineName = jbpmEngineName;
}
/**
* Gets the JBPM Engine instance
*
* @return JBPM Engine
*/
private JBPMEngine getJBPMEngine()
{
if (jbpmEngine == null)
{
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
if (jbpmEngineName == null) jbpmEngineName = "jbpm_engine";
jbpmEngine = (JBPMEngine) factory.getFactory().getBean(jbpmEngineName);
if (jbpmEngine == null) { throw new WorkflowException(
"Failed to retrieve JBPMEngine component"); }
}
return jbpmEngine;
}
@Override
public void create(ExecutionContext executionContext)
{
super.create(executionContext);
getJBPMEngine().setDefaultTaskProperties(this);
}
@Override
public void end(Transition transition)
{
// Force assignment of task if transition is taken, but no owner has yet
// been assigned
if (actorId == null)
{
actorId = AuthenticationUtil.getFullyAuthenticatedUser();
}
// Set task properties on completion of task
// NOTE: Set properties first, so they're available during the
// submission of
// task variables to the process context
Map<QName, Serializable> taskProperties = new HashMap<QName, Serializable>();
Transition outcome = (transition == null) ? token.getNode().getDefaultLeavingTransition()
: transition;
if (outcome != null)
{
taskProperties.put(WorkflowModel.PROP_OUTCOME, outcome.getName());
}
taskProperties.put(WorkflowModel.PROP_STATUS, "Completed");
getJBPMEngine().setTaskProperties(this, taskProperties);
// perform transition
super.end(transition);
if (getTask().getStartState() != null)
{
// if ending a start task, push start task properties to process
// context, if not
// already done
getJBPMEngine().setDefaultWorkflowProperties(this);
// set task description
getJBPMEngine().setDefaultStartTaskDescription(this);
}
}
}

View File

@@ -1,39 +1,39 @@
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;
private String jbpmEngineName;
/**
* @param jbpmEngine the jbpmEngine to set
*/
public void setJbpmEngine(String jbpmEngine)
{
this.jbpmEngineName = jbpmEngine;
}
/*
* (non-Javadoc)
* @see
* org.jbpm.taskmgmt.TaskInstanceFactory#createTaskInstance(org.jbpm.graph
* .exe.ExecutionContext)
*/
public TaskInstance createTaskInstance(ExecutionContext executionContext)
{
WorkflowTaskInstance taskInstance = new WorkflowTaskInstance();
taskInstance.setJbpmEngineName(jbpmEngineName);
return taskInstance;
}
}
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;
private String jbpmEngineName;
/**
* @param jbpmEngine the jbpmEngine to set
*/
public void setJbpmEngine(String jbpmEngine)
{
this.jbpmEngineName = jbpmEngine;
}
/*
* (non-Javadoc)
* @see
* org.jbpm.taskmgmt.TaskInstanceFactory#createTaskInstance(org.jbpm.graph
* .exe.ExecutionContext)
*/
public TaskInstance createTaskInstance(ExecutionContext executionContext)
{
WorkflowTaskInstance taskInstance = new WorkflowTaskInstance();
taskInstance.setJbpmEngineName(jbpmEngineName);
return taskInstance;
}
}