diff --git a/config/alfresco/activiti-context.xml b/config/alfresco/activiti-context.xml
index e243ce6985..f4fbd8a48a 100644
--- a/config/alfresco/activiti-context.xml
+++ b/config/alfresco/activiti-context.xml
@@ -33,6 +33,8 @@
class="org.alfresco.repo.workflow.activiti.AddTaskListenerParseListener">
+
+
@@ -177,6 +179,8 @@
+
+
diff --git a/config/alfresco/content-publishing-context.xml b/config/alfresco/content-publishing-context.xml
index 86f5ad4271..1de1929f1a 100644
--- a/config/alfresco/content-publishing-context.xml
+++ b/config/alfresco/content-publishing-context.xml
@@ -77,7 +77,7 @@
-
+
diff --git a/config/alfresco/web-publishing-context.xml b/config/alfresco/web-publishing-context.xml
new file mode 100644
index 0000000000..1244520a8f
--- /dev/null
+++ b/config/alfresco/web-publishing-context.xml
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+ alfresco/model/publishingModel.xml
+
+
+
+
+
+
+
+
+
+ jbpm
+ alfresco/workflow/publish_web_content_processdefinition.xml
+ text/xml
+ true
+
+
+ activiti
+ alfresco/workflow/publish-web-content.bpmn20.xml
+ text/xml
+ true
+
+
+
+
+
+ alfresco/workflow/publishingWorkflowModel.xml
+
+
+
+
+
+
+
+ alfresco.messages.publishing-service
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/workflow/publish-web-content.bpmn20.xml b/config/alfresco/workflow/publish-web-content.bpmn20.xml
index 61ba4474cc..5a3d5a2138 100644
--- a/config/alfresco/workflow/publish-web-content.bpmn20.xml
+++ b/config/alfresco/workflow/publish-web-content.bpmn20.xml
@@ -6,13 +6,19 @@
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://alfresco.org">
-
+
+
+
+
+
@@ -20,7 +26,7 @@
// Check if the publish should be scheduled or performed immediatly
- if (typeof pubwf_scheduledPublishDate != 'undefined') {
+ if (typeof pubwf_scheduledPublishDate != 'undefined' && pubwf_scheduledPublishDate != null) {
execution.setVariable("schedule", true);
} else {
execution.setVariable("schedule", false);
@@ -39,7 +45,7 @@
-
+
${schedule}
@@ -60,15 +66,15 @@
-
+
-
+
${iso8601PublishDate}
-
.
+ */
+
+package org.alfresco.repo.publishing;
+
+import java.util.List;
+
+import org.alfresco.service.cmr.workflow.WorkflowPath;
+
+
+/**
+ * @author Nick Smith
+ * @author Frederik Heremans
+ * @since 4.0
+ *
+ */
+public class PublishWebContentActivitiTest extends PublishWebContentProcessTest
+{
+ private static final String DEF_NAME = "activiti$publishWebContent";
+
+ @Override
+ protected String getWorkflowDefinitionName()
+ {
+ return DEF_NAME;
+ }
+
+ /**
+ * Activiti has 2 paths: a timer-scope-path and the main execution-path
+ */
+ protected void checkNode(String expNode)
+ {
+ List paths = workflowService.getWorkflowPaths(instanceId);
+ assertEquals(2, paths.size());
+ WorkflowPath path = paths.get(0);
+ assertEquals(expNode, path.getNode().getName());
+ }
+}
diff --git a/source/java/org/alfresco/repo/publishing/PublishWebContentJbpmTest.java b/source/java/org/alfresco/repo/publishing/PublishWebContentJbpmTest.java
index 4fd383a97c..c4af40551a 100644
--- a/source/java/org/alfresco/repo/publishing/PublishWebContentJbpmTest.java
+++ b/source/java/org/alfresco/repo/publishing/PublishWebContentJbpmTest.java
@@ -19,224 +19,21 @@
package org.alfresco.repo.publishing;
-import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
-import static org.alfresco.model.ContentModel.PROP_NAME;
-import static org.alfresco.repo.publishing.PublishingModel.PROP_PUBLISHING_EVENT_STATUS;
-import static org.alfresco.repo.publishing.PublishingModel.PROP_WF_PUBLISHING_EVENT;
-import static org.alfresco.repo.publishing.PublishingModel.PROP_WF_SCHEDULED_PUBLISH_DATE;
-import static org.alfresco.repo.publishing.PublishingModel.TYPE_PUBLISHING_EVENT;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.Serializable;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.alfresco.repo.action.executer.ActionExecuter;
-import org.alfresco.repo.model.Repository;
-import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.repo.transaction.RetryingTransactionHelper;
-import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
-import org.alfresco.repo.workflow.WorkflowModel;
-import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.action.Action;
-import org.alfresco.service.cmr.action.ActionDefinition;
-import org.alfresco.service.cmr.publishing.Status;
-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.WorkflowInstance;
-import org.alfresco.service.cmr.workflow.WorkflowPath;
-import org.alfresco.service.cmr.workflow.WorkflowService;
-import org.alfresco.service.cmr.workflow.WorkflowTask;
-import org.alfresco.service.namespace.QName;
-import org.alfresco.util.ApplicationContextHelper;
-import org.alfresco.util.BaseSpringTest;
-import org.alfresco.util.GUID;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
/**
* @author Nick Smith
+ * @author Frederik Heremans
* @since 4.0
*
*/
-public class PublishWebContentJbpmTest extends BaseSpringTest
+public class PublishWebContentJbpmTest extends PublishWebContentProcessTest
{
private static final String DEF_NAME = "jbpm$publishWebContent";
-
- private ServiceRegistry serviceRegistry;
- private Repository repositoryHelper;
- private ActionExecuter publishEventAction;
- private NodeService nodeService;
- private WorkflowService workflowService;
- private RetryingTransactionHelper transactionHelper;
- private NodeRef event;
- private String instanceId;
- private long threadId;
-
- @Test
- public void testProcessTimers() throws Exception
- {
- final Calendar scheduledTime = Calendar.getInstance();
- scheduledTime.add(Calendar.SECOND, 5);
-
- startWorkflowAndCommit(scheduledTime);
-
- // Should be waiting for scheduled time.
- checkNode("waitForScheduledTime");
-
- // Wait for scheduled time to elapse.
- Thread.sleep(10000);
-
- // Should have ended
- checkEnded(instanceId);
-
- // Check the Publish Event Action was called
- verify(publishEventAction).execute(any(Action.class), any(NodeRef.class));
-
- assertFalse("The action should be run from a different Thread!", Thread.currentThread().getId()==threadId);
- }
-
- public void testProcessNoSchedule() throws Exception
- {
- startWorkflowAndCommit(null);
-
- // Wait for async action to execute
- Thread.sleep(500);
-
- // Should have ended
- checkEnded(instanceId);
-
- // Check the Publish Event Action was called
- verify(publishEventAction).execute(any(Action.class), any(NodeRef.class));
-
- assertFalse("The action should be run from a different Thread!", Thread.currentThread().getId()==threadId);
- }
-
- private void checkEnded(String instanceId2)
- {
- WorkflowInstance instance = workflowService.getWorkflowById(instanceId2);
- if(instance.isActive())
- {
- List paths = workflowService.getWorkflowPaths(instance.getId());
- String nodeName = paths.get(0).getNode().getName();
- fail("Workflow should have ended! At node: " +nodeName);
- }
- }
-
- private void startWorkflowAndCommit(final Calendar scheduledTime)
- {
- RetryingTransactionCallback startWorkflowCallback = new RetryingTransactionCallback()
- {
- public Void execute() throws Throwable
- {
- WorkflowPath path = startWorkflow(scheduledTime);
-
- // End the Start task.
- WorkflowTask startTask = workflowService.getStartTask(path.getInstance().getId());
- workflowService.endTask(startTask.getId(), null);
- return null;
- }
- };
- transactionHelper.doInTransaction(startWorkflowCallback);
- }
-
- private WorkflowPath startWorkflow(Calendar scheduledTime)
- {
- WorkflowDefinition definition = workflowService.getDefinitionByName(DEF_NAME);
- assertNotNull("The definition is null!", definition);
-
- NodeRef pckg = workflowService.createPackage(null);
-
- Map params = new HashMap();
- params.put(PROP_WF_PUBLISHING_EVENT, event);
- params.put(PROP_WF_SCHEDULED_PUBLISH_DATE, scheduledTime);
- params.put(WorkflowModel.ASSOC_PACKAGE, pckg);
-
- WorkflowPath path = workflowService.startWorkflow(definition.getId(), params);
- assertNotNull(path);
- this.instanceId = path.getInstance().getId();
- return path;
- }
-
- private void checkNode(String expNode)
- {
-
- List paths = workflowService.getWorkflowPaths(instanceId);
- assertEquals(1, paths.size());
- WorkflowPath path = paths.get(0);
- assertEquals(expNode, path.getNode().getName());
- }
-
- @Before
- public void onSetUp()
- {
- serviceRegistry = (ServiceRegistry)getApplicationContext().getBean("ServiceRegistry");
- repositoryHelper = (Repository) getApplicationContext().getBean("repositoryHelper");
- publishEventAction = (ActionExecuter) getApplicationContext().getBean("pub_publishEvent");
-
- reset(publishEventAction);
- ActionDefinition actionDef = mock(ActionDefinition.class);
- when(publishEventAction.getActionDefinition()).thenReturn(actionDef);
- // Record thread action is run in.
- Mockito.doAnswer(new Answer()
- {
- public Void answer(InvocationOnMock invocation) throws Throwable
- {
- threadId = Thread.currentThread().getId();
- return null;
- }
- }).when(publishEventAction).execute(any(Action.class), any(NodeRef.class));
-
- this.workflowService = serviceRegistry.getWorkflowService();
- this.nodeService = serviceRegistry.getNodeService();
- this.transactionHelper = serviceRegistry.getRetryingTransactionHelper();
- AuthenticationUtil.setRunAsUser(AuthenticationUtil.getSystemUserName());
- NodeRef companyHome = repositoryHelper.getCompanyHome();
- String name = GUID.generate();
- Map props = new HashMap();
- props.put(PROP_NAME, name);
- props.put(PROP_PUBLISHING_EVENT_STATUS, Status.SCHEDULED.name());
-
- QName assocName = QName.createQNameWithValidLocalName(PublishingModel.NAMESPACE, name);
- ChildAssociationRef eventAssoc = nodeService.createNode(companyHome, ASSOC_CONTAINS, assocName, TYPE_PUBLISHING_EVENT, props);
- this.event = eventAssoc.getChildRef();
- }
-
@Override
- protected String[] getConfigLocations()
+ protected String getWorkflowDefinitionName()
{
- return new String[]
- {
- ApplicationContextHelper.CONFIG_LOCATIONS[0], "classpath:test/alfresco/test-web-publishing--workflow-context.xml"
- };
- }
-
- @After
- public void onTearDown()
- {
- try
- {
- workflowService.cancelWorkflow(instanceId);
- }
- catch (Exception e)
- {
- // NOOP
- }
- nodeService.deleteNode(event);
- AuthenticationUtil.clearCurrentSecurityContext();
+ return DEF_NAME;
}
}
diff --git a/source/java/org/alfresco/repo/publishing/PublishWebContentProcessTest.java b/source/java/org/alfresco/repo/publishing/PublishWebContentProcessTest.java
new file mode 100644
index 0000000000..42fc1826dc
--- /dev/null
+++ b/source/java/org/alfresco/repo/publishing/PublishWebContentProcessTest.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2005-2011 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.publishing;
+
+import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
+import static org.alfresco.model.ContentModel.PROP_NAME;
+import static org.alfresco.repo.publishing.PublishingModel.PROP_PUBLISHING_EVENT_STATUS;
+import static org.alfresco.repo.publishing.PublishingModel.PROP_WF_PUBLISHING_EVENT;
+import static org.alfresco.repo.publishing.PublishingModel.PROP_WF_SCHEDULED_PUBLISH_DATE;
+import static org.alfresco.repo.publishing.PublishingModel.TYPE_PUBLISHING_EVENT;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.Serializable;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.alfresco.repo.action.executer.ActionExecuter;
+import org.alfresco.repo.model.Repository;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.transaction.RetryingTransactionHelper;
+import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
+import org.alfresco.repo.workflow.WorkflowModel;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.action.Action;
+import org.alfresco.service.cmr.action.ActionDefinition;
+import org.alfresco.service.cmr.publishing.Status;
+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.WorkflowInstance;
+import org.alfresco.service.cmr.workflow.WorkflowPath;
+import org.alfresco.service.cmr.workflow.WorkflowService;
+import org.alfresco.service.cmr.workflow.WorkflowTask;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.util.ApplicationContextHelper;
+import org.alfresco.util.BaseSpringTest;
+import org.alfresco.util.GUID;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+/**
+ * @author Nick Smith
+ * @author Frederik Heremans
+ *
+ * @since 4.0
+ *
+ */
+public abstract class PublishWebContentProcessTest extends BaseSpringTest
+{
+ protected ServiceRegistry serviceRegistry;
+ protected Repository repositoryHelper;
+ protected ActionExecuter publishEventAction;
+
+ protected NodeService nodeService;
+ protected WorkflowService workflowService;
+ protected RetryingTransactionHelper transactionHelper;
+ protected NodeRef event;
+ protected String instanceId;
+ protected long threadId;
+
+ /**
+ * Get definition to use
+ */
+ protected abstract String getWorkflowDefinitionName();
+
+ @Test
+ public void testProcessTimers() throws Exception
+ {
+ final Calendar scheduledTime = Calendar.getInstance();
+ scheduledTime.add(Calendar.SECOND, 5);
+
+ startWorkflowAndCommit(scheduledTime);
+
+ // Should be waiting for scheduled time.
+ checkNode("waitForScheduledTime");
+
+ // Wait for scheduled time to elapse.
+ Thread.sleep(10000);
+
+ // Should have ended
+ checkEnded(instanceId);
+
+ // Check the Publish Event Action was called
+ verify(publishEventAction).execute(any(Action.class), any(NodeRef.class));
+
+ assertFalse("The action should be run from a different Thread!", Thread.currentThread().getId()==threadId);
+ }
+
+ public void testProcessNoSchedule() throws Exception
+ {
+ startWorkflowAndCommit(null);
+
+ // Wait for async action to execute
+ Thread.sleep(500);
+
+ // Should have ended
+ checkEnded(instanceId);
+
+ // Check the Publish Event Action was called
+ verify(publishEventAction).execute(any(Action.class), any(NodeRef.class));
+
+ assertFalse("The action should be run from a different Thread!", Thread.currentThread().getId()==threadId);
+ }
+
+ private void checkEnded(String instanceId2)
+ {
+ WorkflowInstance instance = workflowService.getWorkflowById(instanceId2);
+ if(instance.isActive())
+ {
+ List paths = workflowService.getWorkflowPaths(instance.getId());
+ String nodeName = paths.get(0).getNode().getName();
+ fail("Workflow should have ended! At node: " +nodeName);
+ }
+ }
+
+ private void startWorkflowAndCommit(final Calendar scheduledTime)
+ {
+ RetryingTransactionCallback startWorkflowCallback = new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ WorkflowPath path = startWorkflow(scheduledTime);
+
+ // End the Start task.
+ WorkflowTask startTask = workflowService.getStartTask(path.getInstance().getId());
+ workflowService.endTask(startTask.getId(), null);
+ return null;
+ }
+ };
+ transactionHelper.doInTransaction(startWorkflowCallback);
+ }
+
+ private WorkflowPath startWorkflow(Calendar scheduledTime)
+ {
+ WorkflowDefinition definition = workflowService.getDefinitionByName(getWorkflowDefinitionName());
+ assertNotNull("The definition is null!", definition);
+
+ NodeRef pckg = workflowService.createPackage(null);
+
+ Map params = new HashMap();
+ params.put(PROP_WF_PUBLISHING_EVENT, event);
+ params.put(PROP_WF_SCHEDULED_PUBLISH_DATE, scheduledTime);
+ params.put(WorkflowModel.ASSOC_PACKAGE, pckg);
+
+ WorkflowPath path = workflowService.startWorkflow(definition.getId(), params);
+ assertNotNull(path);
+ this.instanceId = path.getInstance().getId();
+ return path;
+ }
+
+ protected void checkNode(String expNode)
+ {
+ List paths = workflowService.getWorkflowPaths(instanceId);
+ assertEquals(1, paths.size());
+ WorkflowPath path = paths.get(0);
+ assertEquals(expNode, path.getNode().getName());
+ }
+
+ @Before
+ public void onSetUp()
+ {
+ serviceRegistry = (ServiceRegistry)getApplicationContext().getBean("ServiceRegistry");
+ repositoryHelper = (Repository) getApplicationContext().getBean("repositoryHelper");
+ publishEventAction = (ActionExecuter) getApplicationContext().getBean("pub_publishEvent");
+
+ reset(publishEventAction);
+ ActionDefinition actionDef = mock(ActionDefinition.class);
+ when(publishEventAction.getActionDefinition()).thenReturn(actionDef);
+ // Record thread action is run in.
+ Mockito.doAnswer(new Answer()
+ {
+ public Void answer(InvocationOnMock invocation) throws Throwable
+ {
+ threadId = Thread.currentThread().getId();
+ return null;
+ }
+ }).when(publishEventAction).execute(any(Action.class), any(NodeRef.class));
+
+ this.workflowService = serviceRegistry.getWorkflowService();
+ this.nodeService = serviceRegistry.getNodeService();
+ this.transactionHelper = serviceRegistry.getRetryingTransactionHelper();
+ AuthenticationUtil.setRunAsUser(AuthenticationUtil.getSystemUserName());
+ NodeRef companyHome = repositoryHelper.getCompanyHome();
+ String name = GUID.generate();
+ Map props = new HashMap();
+ props.put(PROP_NAME, name);
+ props.put(PROP_PUBLISHING_EVENT_STATUS, Status.SCHEDULED.name());
+
+ QName assocName = QName.createQNameWithValidLocalName(PublishingModel.NAMESPACE, name);
+ ChildAssociationRef eventAssoc = nodeService.createNode(companyHome, ASSOC_CONTAINS, assocName, TYPE_PUBLISHING_EVENT, props);
+ this.event = eventAssoc.getChildRef();
+ }
+
+ @Override
+ protected String[] getConfigLocations()
+ {
+ return new String[]
+ {
+ ApplicationContextHelper.CONFIG_LOCATIONS[0], "classpath:test/alfresco/test-web-publishing--workflow-context.xml"
+ };
+ }
+
+ @After
+ public void onTearDown()
+ {
+ try
+ {
+ workflowService.cancelWorkflow(instanceId);
+ }
+ catch (Exception e)
+ {
+ // NOOP
+ }
+ nodeService.deleteNode(event);
+ AuthenticationUtil.clearCurrentSecurityContext();
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/publishing/PublishingQueueImplTest.java b/source/java/org/alfresco/repo/publishing/PublishingQueueImplTest.java
index f60367620e..062122c1ea 100644
--- a/source/java/org/alfresco/repo/publishing/PublishingQueueImplTest.java
+++ b/source/java/org/alfresco/repo/publishing/PublishingQueueImplTest.java
@@ -132,7 +132,7 @@ public class PublishingQueueImplTest extends AbstractPublishingIntegrationTest
WorkflowInstance instance = workflowService.getWorkflowById(wfId);
assertNotNull(instance);
List paths = workflowService.getWorkflowPaths(wfId);
- assertEquals(1, paths.size());
+ assertEquals(2, paths.size());
Map props = workflowService.getPathProperties(paths.get(0).getId());
assertEquals(eventNode, props.get(PROP_WF_PUBLISHING_EVENT));
assertEquals(schedule, props.get(PROP_WF_SCHEDULED_PUBLISH_DATE));
diff --git a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java
index 2369442a7f..17a3eed923 100644
--- a/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java
+++ b/source/java/org/alfresco/repo/workflow/activiti/ActivitiWorkflowEngine.java
@@ -46,6 +46,7 @@ import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.RepositoryServiceImpl;
+import org.activiti.engine.impl.bpmn.behavior.ReceiveTaskActivityBehavior;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.bpmn.deployer.BpmnDeployer;
import org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator;
@@ -597,6 +598,16 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
}
return null;
}
+
+ private boolean isReceiveTask(PvmActivity act)
+ {
+ if(act instanceof ActivityImpl)
+ {
+ ActivityImpl actImpl = (ActivityImpl) act;
+ return (actImpl.getActivityBehavior() instanceof ReceiveTaskActivityBehavior);
+ }
+ return false;
+ }
private Collection findUserTasks(PvmActivity startEvent)
{
@@ -608,6 +619,17 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
return userTasks.values();
}
+
+ private boolean isFirstActivity(PvmActivity activity, ReadOnlyProcessDefinition procDef)
+ {
+ if(procDef.getInitial().getOutgoingTransitions().size() == 1)
+ {
+ if(procDef.getInitial().getOutgoingTransitions().get(0).getDestination().equals(activity)) {
+ return true;
+ }
+ }
+ return false;
+ }
private void findUserTasks(PvmActivity currentActivity, Map userTasks)
{
@@ -974,10 +996,14 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
// Start the process-instance
ProcessInstance instance = runtimeService.startProcessInstanceById(processDefId, variables);
-
- // Set ID of workflowinstance after ProcessInstance is created
- runtimeService.setVariable(instance.getId(), WorkflowConstants.PROP_WORKFLOW_INSTANCE_ID, createGlobalId(instance.getId()));
- return typeConverter.convert((Execution)instance);
+ if(instance.isEnded())
+ {
+ return typeConverter.buildCompletedPath(instance.getId(), instance.getId());
+ }
+ else
+ {
+ return typeConverter.convert((Execution)instance);
+ }
}
catch (ActivitiException ae)
{
@@ -1299,8 +1325,35 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
// Set start task end date on the process
runtimeService.setVariable(processInstanceId, ActivitiConstants.PROP_START_TASK_END_DATE, new Date());
- // Return virtual start task for the execution, it's safe to use the processInstanceId
- return typeConverter.getVirtualStartTask(processInstanceId, false);
+ // Check if the current activity is a signalTask and the first activity in the process,
+ // this is a workaround for processes without any task/waitstates that should otherwise end
+ // when they are started.
+ ProcessInstance processInstance = activitiUtil.getProcessInstance(processInstanceId);
+ String currentActivity = ((ExecutionEntity)processInstance).getActivityId();
+
+ ReadOnlyProcessDefinition procDef = activitiUtil.getDeployedProcessDefinition(processInstance.getProcessDefinitionId());
+ PvmActivity activity = procDef.findActivity(currentActivity);
+ if(isReceiveTask(activity) && isFirstActivity(activity, procDef))
+ {
+ // Signal the process to start flowing, beginning from the recieve task
+ 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);
+ }
+
}
/**
diff --git a/source/java/org/alfresco/repo/workflow/activiti/AddTaskListenerParseListener.java b/source/java/org/alfresco/repo/workflow/activiti/AddTaskListenerParseListener.java
index e835f7bf41..3c102458b5 100644
--- a/source/java/org/alfresco/repo/workflow/activiti/AddTaskListenerParseListener.java
+++ b/source/java/org/alfresco/repo/workflow/activiti/AddTaskListenerParseListener.java
@@ -18,6 +18,7 @@
*/
package org.alfresco.repo.workflow.activiti;
+import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.TaskListener;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.bpmn.parser.BpmnParseListener;
@@ -42,6 +43,7 @@ public class AddTaskListenerParseListener implements BpmnParseListener
{
private TaskListener completeTaskListener;
private TaskListener createTaskListener;
+ private ExecutionListener processCreateListener;
@Override
public void parseUserTask(Element userTaskElement, ScopeImpl scope, ActivityImpl activity)
@@ -64,7 +66,7 @@ public class AddTaskListenerParseListener implements BpmnParseListener
@Override
public void parseProcess(Element processElement, ProcessDefinitionEntity processDefinition)
{
- // Nothing to do here
+ processDefinition.addExecutionListener(ExecutionListener.EVENTNAME_START, processCreateListener);
}
@Override
@@ -196,5 +198,10 @@ public class AddTaskListenerParseListener implements BpmnParseListener
{
this.createTaskListener = createTaskListener;
}
+
+ public void setProcessCreateListener(ExecutionListener processCreateListener)
+ {
+ this.processCreateListener = processCreateListener;
+ }
}
diff --git a/source/java/org/alfresco/repo/workflow/activiti/listener/ConvertDateToISO8601.java b/source/java/org/alfresco/repo/workflow/activiti/listener/ConvertDateToISO8601.java
index 57d1224d28..eb3c79cc16 100644
--- a/source/java/org/alfresco/repo/workflow/activiti/listener/ConvertDateToISO8601.java
+++ b/source/java/org/alfresco/repo/workflow/activiti/listener/ConvertDateToISO8601.java
@@ -19,6 +19,7 @@
package org.alfresco.repo.workflow.activiti.listener;
+import java.util.Calendar;
import java.util.Date;
import org.activiti.engine.delegate.DelegateExecution;
@@ -61,7 +62,19 @@ public class ConvertDateToISO8601 implements ExecutionListener
throw new IllegalArgumentException("Both fields 'source' and 'target' shoudl be set");
}
- Date dateToConvert = (Date) execution.getVariable(sourceVarName);
+ Object dateVar = execution.getVariable(sourceVarName);
+ Date dateToConvert = null;
+
+ // Accept null, Date or Calendar as value
+ if(dateVar != null) {
+ if(dateVar instanceof Date) {
+ dateToConvert = (Date) execution.getVariable(sourceVarName);
+ } else if(dateVar instanceof Calendar) {
+ dateToConvert = ((Calendar) execution.getVariable(sourceVarName)).getTime();
+ } else {
+ throw new IllegalArgumentException("Variable with name: " + sourceVarName + " must be a Date or a Calendar");
+ }
+ }
if(dateToConvert != null) {
// Convert the date to ISO-8601 format
String convertedDate = ISO8601DateFormat.format(dateToConvert);
diff --git a/source/java/org/alfresco/repo/workflow/activiti/listener/ProcessStartExecutionListener.java b/source/java/org/alfresco/repo/workflow/activiti/listener/ProcessStartExecutionListener.java
new file mode 100644
index 0000000000..c72cdd4f83
--- /dev/null
+++ b/source/java/org/alfresco/repo/workflow/activiti/listener/ProcessStartExecutionListener.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2005-2011 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.workflow.activiti.listener;
+
+import org.activiti.engine.delegate.DelegateExecution;
+import org.activiti.engine.delegate.ExecutionListener;
+import org.alfresco.repo.workflow.BPMEngineRegistry;
+import org.alfresco.repo.workflow.WorkflowConstants;
+import org.alfresco.repo.workflow.activiti.ActivitiConstants;
+
+/**
+ * An {@link ExecutionListener} that set all additional variables that are needed
+ * when process starts.
+ *
+ * @author Frederik Heremans
+ */
+public class ProcessStartExecutionListener implements ExecutionListener
+{
+
+ public void notify(DelegateExecution execution) throws Exception
+ {
+ // Add the workflow ID
+ execution.setVariable(WorkflowConstants.PROP_WORKFLOW_INSTANCE_ID, BPMEngineRegistry
+ .createGlobalId(ActivitiConstants.ENGINE_ID, execution.getId()));
+
+ }
+}