diff --git a/config/alfresco/model/bpmModel.xml b/config/alfresco/model/bpmModel.xml
index 1104cf8941..78cb147d52 100644
--- a/config/alfresco/model/bpmModel.xml
+++ b/config/alfresco/model/bpmModel.xml
@@ -335,6 +335,18 @@
+
+
+
+
+
+
+ bpm:startTask
+
+ bpm:endAutomatically
+
+
+
@@ -490,6 +502,11 @@
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/workflow/AlfrescoBpmEngine.java b/source/java/org/alfresco/repo/workflow/AlfrescoBpmEngine.java
index 99821c2d17..9b092c1724 100644
--- a/source/java/org/alfresco/repo/workflow/AlfrescoBpmEngine.java
+++ b/source/java/org/alfresco/repo/workflow/AlfrescoBpmEngine.java
@@ -24,6 +24,7 @@ import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
/**
* @author Nick Smith
@@ -58,7 +59,8 @@ public abstract class AlfrescoBpmEngine extends BPMEngine
throw new WorkflowException("NamespaceService not specified");
}
WorkflowQNameConverter qNameConverter = new WorkflowQNameConverter(namespaceService);
- this.factory = new WorkflowObjectFactory(qNameConverter, tenantService, messageService, dictionaryService, getEngineId());
+ QName defaultStartTaskType = getDefaultStartTaskType();
+ this.factory = new WorkflowObjectFactory(qNameConverter, tenantService, messageService, dictionaryService, getEngineId(), defaultStartTaskType);
}
/**
@@ -114,4 +116,6 @@ public abstract class AlfrescoBpmEngine extends BPMEngine
{
this.authorityManager = authorityManager;
}
+
+ protected abstract QName getDefaultStartTaskType();
}
diff --git a/source/java/org/alfresco/repo/workflow/WorkflowModel.java b/source/java/org/alfresco/repo/workflow/WorkflowModel.java
index 4e8e99a439..1759ed7756 100644
--- a/source/java/org/alfresco/repo/workflow/WorkflowModel.java
+++ b/source/java/org/alfresco/repo/workflow/WorkflowModel.java
@@ -73,6 +73,12 @@ public interface WorkflowModel
// 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");
diff --git a/source/java/org/alfresco/repo/workflow/WorkflowObjectFactory.java b/source/java/org/alfresco/repo/workflow/WorkflowObjectFactory.java
index dcd89a9702..4727e03ec9 100644
--- a/source/java/org/alfresco/repo/workflow/WorkflowObjectFactory.java
+++ b/source/java/org/alfresco/repo/workflow/WorkflowObjectFactory.java
@@ -62,18 +62,20 @@ public class WorkflowObjectFactory
private final MessageService messageService;
private final DictionaryService dictionaryService;
private final String engineId;
+ private final QName defaultStartTaskType;
public WorkflowObjectFactory(WorkflowQNameConverter qNameConverter,
TenantService tenantService,
MessageService messageService,
DictionaryService dictionaryService,
- String engineId)
+ String engineId, QName defaultStartTaskType)
{
this.tenantService = tenantService;
this.messageService = messageService;
this.dictionaryService = dictionaryService;
this.engineId = engineId;
this.qNameConverter = qNameConverter;
+ this.defaultStartTaskType = defaultStartTaskType;
}
public String buildGlobalId(String localId)
@@ -390,7 +392,7 @@ public class WorkflowObjectFactory
}
if (typeDef == null)
{
- QName defaultTypeName = isStart? WorkflowModel.TYPE_START_TASK : WorkflowModel.TYPE_WORKFLOW_TASK;
+ QName defaultTypeName = isStart? defaultStartTaskType : WorkflowModel.TYPE_WORKFLOW_TASK;
typeDef = dictionaryService.getType(defaultTypeName);
if (typeDef == null)
{
diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiTypeConverter.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiTypeConverter.java
index b6932811bf..9ad1ebd0f7 100644
--- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiTypeConverter.java
+++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiTypeConverter.java
@@ -357,14 +357,31 @@ public class ActivitiTypeConverter
taskDef, taskDef.getId(), defaultTitle, defaultDescription, state, path, properties);
}
- public WorkflowTask getVirtualStartTask(String executionId, boolean inProgress)
+ public WorkflowTask getVirtualStartTask(String processInstanceId, Boolean inProgress)
{
- Execution execution = runtimeService.createExecutionQuery().executionId(executionId).singleResult();
- ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
- .processInstanceId(execution.getProcessInstanceId())
- .singleResult();
-
- String id = ActivitiConstants.START_TASK_PREFIX + execution.getProcessInstanceId();
+ ProcessInstance processInstance = activitiUtil.getProcessInstance(processInstanceId);
+ if(processInstance != null)
+ {
+ if(null == inProgress)
+ {
+ inProgress = isStartTaskActive(processInstanceId);
+ }
+ return getVirtualStartTask(processInstance, inProgress);
+ }
+ HistoricProcessInstance historicProcessInstance = activitiUtil.getHistoricProcessInstance(processInstanceId);
+ return getVirtualStartTask(historicProcessInstance);
+ }
+
+ public boolean isStartTaskActive(String processInstanceId)
+ {
+ Object endDate = runtimeService.getVariable(processInstanceId, ActivitiConstants.PROP_START_TASK_END_DATE);
+ return endDate == null;
+ }
+
+ private WorkflowTask getVirtualStartTask(ProcessInstance processInstance, boolean inProgress)
+ {
+ String processInstanceId = processInstance.getId();
+ String id = ActivitiConstants.START_TASK_PREFIX + processInstanceId;
WorkflowTaskState state = null;
if(inProgress)
@@ -376,7 +393,7 @@ public class ActivitiTypeConverter
state = WorkflowTaskState.COMPLETED;
}
- WorkflowPath path = convert(execution);
+ WorkflowPath path = convert((Execution)processInstance);
// Convert start-event to start-task Node
ReadOnlyProcessDefinition procDef = activitiUtil.getDeployedProcessDefinition(processInstance.getProcessDefinitionId());
@@ -393,7 +410,7 @@ public class ActivitiTypeConverter
// Add properties based on HistoricProcessInstance
HistoricProcessInstance historicProcessInstance = historyService
.createHistoricProcessInstanceQuery()
- .processInstanceId(execution.getProcessInstanceId())
+ .processInstanceId(processInstance.getId())
.singleResult();
Map properties = propertyConverter.getStartTaskProperties(historicProcessInstance, taskDefId, !inProgress);
@@ -406,7 +423,7 @@ public class ActivitiTypeConverter
taskDef, taskDef.getId(), defaultTitle, defaultDescription, state, path, properties);
}
- public WorkflowTask getVirtualStartTask(HistoricProcessInstance historicProcessInstance)
+ private WorkflowTask getVirtualStartTask(HistoricProcessInstance historicProcessInstance)
{
if(historicProcessInstance == null)
{
@@ -416,18 +433,9 @@ public class ActivitiTypeConverter
String processInstanceId = historicProcessInstance.getId();
String id = ActivitiConstants.START_TASK_PREFIX + processInstanceId;
- WorkflowTaskState state = null;
-
- boolean completed = historicProcessInstance.getEndTime() != null;
- if(completed)
- {
- state = WorkflowTaskState.COMPLETED;
- }
- else
- {
- state = WorkflowTaskState.IN_PROGRESS;
- }
-
+ // Since the process instance is complete the Start Task must be complete!
+ WorkflowTaskState state = WorkflowTaskState.COMPLETED;
+
// We use the process-instance ID as execution-id. It's ended anyway
WorkflowPath path = buildCompletedPath(processInstanceId, processInstanceId);
if(path == null)
@@ -442,6 +450,7 @@ public class ActivitiTypeConverter
String taskDefId = activitiUtil.getStartFormKey(historicProcessInstance.getProcessDefinitionId());
WorkflowTaskDefinition taskDef = factory.createTaskDefinition(taskDefId, startNode, taskDefId, true);
+ boolean completed = historicProcessInstance.getEndTime() != null;
Map properties = propertyConverter.getStartTaskProperties(historicProcessInstance, taskDefId, completed);
// TODO: Figure out what name/description should be used for the start-task, start event's name?
diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java
index c2b364af0c..39cb630add 100644
--- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java
+++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java
@@ -33,6 +33,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.FormService;
@@ -81,6 +82,7 @@ import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.repo.workflow.WorkflowNodeConverter;
import org.alfresco.repo.workflow.WorkflowObjectFactory;
import org.alfresco.repo.workflow.activiti.properties.ActivitiPropertyConverter;
+import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -689,46 +691,42 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
/**
* {@inheritDoc}
*/
-
public List getTasksForWorkflowPath(String pathId)
{
- try
- {
- // Extract the Activiti ID from the path
- String executionId = getExecutionIdFromPath(pathId);
- if(executionId == null)
- {
- throw new WorkflowException(messageService.getMessage(ERR_GET_WORKFLOW_TOKEN_INVALID, pathId));
- }
-
- // Check if the execution exists
- Execution execution = runtimeService.createExecutionQuery().executionId(executionId).singleResult();
- if(execution == null)
- {
- throw new WorkflowException(messageService.getMessage(ERR_GET_WORKFLOW_TOKEN_NULL, pathId));
- }
-
- List resultList = new ArrayList();
-
- // Check if workflow's start task has been completed. If not, return the virtual task
- // Otherwise, just return the runtime activiti tasks
- Date startTaskEndDate = (Date) runtimeService.getVariable(execution.getProcessInstanceId(),
- ActivitiConstants.PROP_START_TASK_END_DATE);
- boolean startTaskEnded = (startTaskEndDate != null);
-
- if(startTaskEnded)
- {
- List tasks = taskService.createTaskQuery().executionId(executionId).list();
- for(Task task : tasks)
- {
- resultList.add(typeConverter.convert(task));
- }
- }
- else
- {
- resultList.add(typeConverter.getVirtualStartTask(executionId, true));
- }
- return resultList;
+ try
+ {
+ // Extract the Activiti ID from the path
+ String executionId = getExecutionIdFromPath(pathId);
+ if (executionId == null)
+ {
+ throw new WorkflowException(messageService.getMessage(ERR_GET_WORKFLOW_TOKEN_INVALID, pathId));
+ }
+
+ // Check if the execution exists
+ Execution execution = runtimeService.createExecutionQuery().executionId(executionId).singleResult();
+ if (execution == null)
+ {
+ throw new WorkflowException(messageService.getMessage(ERR_GET_WORKFLOW_TOKEN_NULL, pathId));
+ }
+
+ // Check if workflow's start task has been completed. If not, return
+ // the virtual task
+ // Otherwise, just return the runtime Activiti tasks
+ String processInstanceId = execution.getProcessInstanceId();
+ ArrayList resultList = new ArrayList();
+ if (typeConverter.isStartTaskActive(processInstanceId))
+ {
+ resultList.add(typeConverter.getVirtualStartTask(processInstanceId, true));
+ }
+ else
+ {
+ List tasks = taskService.createTaskQuery().executionId(executionId).list();
+ for (Task task : tasks)
+ {
+ resultList.add(typeConverter.convert(task));
+ }
+ }
+ return resultList;
}
catch (ActivitiException ae)
{
@@ -736,7 +734,7 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
throw new WorkflowException(msg, ae);
}
}
-
+
protected String getExecutionIdFromPath(String workflowPath)
{
if(workflowPath != null)
@@ -1017,7 +1015,9 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
}
else
{
- return typeConverter.convert((Execution)instance);
+ WorkflowPath path = typeConverter.convert((Execution)instance);
+ endStartTaskAutomatically(path, instance);
+ return path;
}
}
catch (ActivitiException ae)
@@ -1026,6 +1026,23 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
throw new WorkflowException(msg, ae);
}
}
+
+ /**
+ * @param path
+ * @param instance
+ */
+ private void endStartTaskAutomatically(WorkflowPath path, ProcessInstance instance)
+ {
+ // Check if StartTask Needs to be ended automatically
+ WorkflowDefinition definition = path.getInstance().getDefinition();
+ TypeDefinition metadata = definition.getStartTaskDefinition().getMetadata();
+ Set aspects = metadata.getDefaultAspectNames();
+ if(aspects.contains(WorkflowModel.ASPECT_END_AUTOMATICALLY))
+ {
+ String taskId = ActivitiConstants.START_TASK_PREFIX + instance.getId();
+ endStartTask(taskId);
+ }
+ }
/**
* {@inheritDoc}
@@ -1296,7 +1313,7 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
// Check if the task is a virtual start task
if(localTaskId.startsWith(ActivitiConstants.START_TASK_PREFIX))
{
- return endStartTask(taskId, localTaskId, transition);
+ return endStartTask(localTaskId);
}
return endNormalTask(taskId, localTaskId, transition);
@@ -1356,11 +1373,15 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
propertyConverter.updateTask(task, updates, null, null);
}
- private WorkflowTask endStartTask(String taskId, String localTaskId, String transition)
+ private WorkflowTask endStartTask(String localTaskId)
{
// We don't end a task, we set a variable on the process-instance
// to indicate that it's started
String processInstanceId = localTaskId.replace(ActivitiConstants.START_TASK_PREFIX, "");
+ if(false == typeConverter.isStartTaskActive(processInstanceId))
+ {
+ return typeConverter.getVirtualStartTask(processInstanceId, false);
+ }
// Set start task end date on the process
runtimeService.setVariable(processInstanceId, ActivitiConstants.PROP_START_TASK_END_DATE, new Date());
@@ -1379,22 +1400,10 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
runtimeService.signal(processInstanceId);
// It's possible the process has ended after signalling the receive task
- processInstance = activitiUtil.getProcessInstance(processInstanceId);
- if (processInstance != null)
- {
- return typeConverter.getVirtualStartTask(processInstanceId, false);
- }
- else
- {
- return typeConverter.getVirtualStartTask(activitiUtil.getHistoricProcessInstance(processInstanceId));
- }
}
- else
- {
- // Return virtual start task for the execution, it's safe to use the processInstanceId
- return typeConverter.getVirtualStartTask(processInstanceId, false);
- }
-
+ // Return virtual start task for the execution, it's safe to use the
+ // processInstanceId
+ return typeConverter.getVirtualStartTask(processInstanceId, false);
}
/**
@@ -1515,7 +1524,7 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
if(localId.startsWith(ActivitiConstants.START_TASK_PREFIX))
{
String processInstanceId = localId.replace(ActivitiConstants.START_TASK_PREFIX ,"");
- return getVirtualStartTaskForProcessInstance(processInstanceId);
+ return typeConverter.getVirtualStartTask(processInstanceId, null);
}
else
{
@@ -1884,8 +1893,7 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
// Only return start-task when a process or task id is set
if(processInstanceId != null)
{
- // Extract processInstanceId
- WorkflowTask workflowTask = getVirtualStartTaskForProcessInstance(processInstanceId);
+ WorkflowTask workflowTask = typeConverter.getVirtualStartTask(processInstanceId, null);
if(workflowTask != null)
{
boolean startTaskMatches = isStartTaskMatching(workflowTask, query);
@@ -2033,32 +2041,7 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
public WorkflowTask getStartTask(String workflowInstanceId)
{
String instanceId = createLocalId(workflowInstanceId);
- return getVirtualStartTaskForProcessInstance(instanceId);
- }
-
- public WorkflowTask getVirtualStartTaskForProcessInstance(String processInstanceId)
- {
-
- ProcessInstance runningInstance = runtimeService.createProcessInstanceQuery()
- .processInstanceId(processInstanceId)
- .singleResult();
-
- if(runningInstance != null)
- {
- // Check the process instance variable to see if start-task has been completed
- Date startTaskEndDate = (Date) runtimeService.getVariable(runningInstance.getProcessInstanceId(),
- ActivitiConstants.PROP_START_TASK_END_DATE);
- boolean startTaskEnded = (startTaskEndDate != null);
- return typeConverter.getVirtualStartTask(runningInstance.getId(), !startTaskEnded);
- }
- else
- {
- HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()
- .processInstanceId(processInstanceId)
- .singleResult();
-
- return typeConverter.getVirtualStartTask(hpi);
- }
+ return typeConverter.getVirtualStartTask(instanceId, null);
}
/**
diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowManagerFactory.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowManagerFactory.java
index 2d27dd937b..4b3199338d 100644
--- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowManagerFactory.java
+++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowManagerFactory.java
@@ -26,6 +26,7 @@ import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.workflow.BPMEngineRegistry;
import org.alfresco.repo.workflow.DefaultWorkflowPropertyHandler;
import org.alfresco.repo.workflow.WorkflowAuthorityManager;
+import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.repo.workflow.WorkflowObjectFactory;
import org.alfresco.repo.workflow.WorkflowPropertyHandlerRegistry;
import org.alfresco.repo.workflow.WorkflowQNameConverter;
@@ -37,6 +38,7 @@ import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
import org.springframework.beans.factory.FactoryBean;
/**
@@ -90,7 +92,8 @@ public class ActivitiWorkflowManagerFactory implements FactoryBean tasks = workflowService.getTasksForWorkflowPath(path.getId());
+ assertEquals(1, tasks.size());
+ String taskName = tasks.get(0).getName();
+ assertEquals("bpm_foo_task", taskName);
+ }
+
@Override
protected void checkTaskQueryStartTaskCompleted(String workflowInstanceId, WorkflowTask startTask)
{
diff --git a/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPropertyConverter.java b/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPropertyConverter.java
index 906979453e..9224dc848a 100644
--- a/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPropertyConverter.java
+++ b/source/java/org/alfresco/repo/workflow/activiti/properties/ActivitiPropertyConverter.java
@@ -852,12 +852,10 @@ public class ActivitiPropertyConverter
*/
private List getMissingMandatoryTaskProperties(DelegateTask task)
{
-
TypeDefinition typeDefinition = typeManager.getFullTaskDefinition(task);
// retrieve properties of task
Map existingValues = getTaskProperties(task, typeDefinition, false);
- // retrieve definition of task
Map propertyDefs = typeDefinition.getProperties();
Map assocDefs = typeDefinition.getAssociations();
diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java
index c4f26c0951..80d4f0804d 100644
--- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java
+++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java
@@ -3417,7 +3417,7 @@ public class JBPMEngine extends AlfrescoBpmEngine implements WorkflowEngine
{
if (node instanceof HibernateProxy)
{
- Node realNode = (Node)((HibernateProxy)node).getHibernateLazyInitializer().getImplementation();
+ Node realNode = (Node)((HibernateProxy)node).getHibernateLazyInitializer().getImplementation();
return realNode;
}
else
@@ -3426,4 +3426,10 @@ public class JBPMEngine extends AlfrescoBpmEngine implements WorkflowEngine
}
}
+ @Override
+ protected QName getDefaultStartTaskType()
+ {
+ return WorkflowModel.TYPE_START_TASK;
+ }
+
}