mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
ALF-9693: Social publishing now using the activiti process definition + fixed issue with activiti process without wait-state
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@30078 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -33,6 +33,8 @@
|
|||||||
class="org.alfresco.repo.workflow.activiti.AddTaskListenerParseListener">
|
class="org.alfresco.repo.workflow.activiti.AddTaskListenerParseListener">
|
||||||
<property name="createTaskListener" ref="activitiCreateTaskListener" />
|
<property name="createTaskListener" ref="activitiCreateTaskListener" />
|
||||||
<property name="completeTaskListener" ref="activitiCompleteTaskListener" />
|
<property name="completeTaskListener" ref="activitiCompleteTaskListener" />
|
||||||
|
<property name="processCreateListener" ref="activitiProcessCreateListener" />
|
||||||
|
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
@@ -178,6 +180,8 @@
|
|||||||
<property name="services" ref="ServiceRegistry" />
|
<property name="services" ref="ServiceRegistry" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="activitiProcessCreateListener" class="org.alfresco.repo.workflow.activiti.listener.ProcessStartExecutionListener" />
|
||||||
|
|
||||||
<bean id="activitiRepositoryService" factory-bean="activitiProcessEngine"
|
<bean id="activitiRepositoryService" factory-bean="activitiProcessEngine"
|
||||||
factory-method="getRepositoryService" />
|
factory-method="getRepositoryService" />
|
||||||
<bean id="activitiRuntimeService" factory-bean="activitiProcessEngine"
|
<bean id="activitiRuntimeService" factory-bean="activitiProcessEngine"
|
||||||
|
@@ -77,7 +77,7 @@
|
|||||||
<property name="permissionService" ref="PermissionService" />
|
<property name="permissionService" ref="PermissionService" />
|
||||||
<property name="transferManifestNodeFactory" ref="transferManifestNodeFactory" />
|
<property name="transferManifestNodeFactory" ref="transferManifestNodeFactory" />
|
||||||
<property name="versionService" ref="VersionService" />
|
<property name="versionService" ref="VersionService" />
|
||||||
<property name="workflowEngineId" value="jbpm" />
|
<property name="workflowEngineId" value="activiti" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
|
119
config/alfresco/web-publishing-context.xml
Normal file
119
config/alfresco/web-publishing-context.xml
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||||
|
|
||||||
|
<beans>
|
||||||
|
<bean id="publishingService_dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap">
|
||||||
|
<property name="models">
|
||||||
|
<list>
|
||||||
|
<value>alfresco/model/publishingModel.xml</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Bootstrap the publishing process definition -->
|
||||||
|
<bean parent="workflowDeployer">
|
||||||
|
<property name="workflowDefinitions">
|
||||||
|
<list>
|
||||||
|
<props>
|
||||||
|
<prop key="engineId">jbpm</prop>
|
||||||
|
<prop key="location">alfresco/workflow/publish_web_content_processdefinition.xml</prop>
|
||||||
|
<prop key="mimetype">text/xml</prop>
|
||||||
|
<prop key="redeploy">true</prop>
|
||||||
|
</props>
|
||||||
|
<props>
|
||||||
|
<prop key="engineId">activiti</prop>
|
||||||
|
<prop key="location">alfresco/workflow/publish-web-content.bpmn20.xml</prop>
|
||||||
|
<prop key="mimetype">text/xml</prop>
|
||||||
|
<prop key="redeploy">true</prop>
|
||||||
|
</props>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
<property name="models">
|
||||||
|
<list>
|
||||||
|
<value>alfresco/workflow/publishingWorkflowModel.xml</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="publishingResourceBundles" class="org.alfresco.i18n.ResourceBundleBootstrapComponent">
|
||||||
|
<property name="resourceBundles">
|
||||||
|
<list>
|
||||||
|
<value>alfresco.messages.publishing-service</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Channel Service -->
|
||||||
|
<bean id="channelService" class="org.alfresco.repo.publishing.ChannelServiceImpl">
|
||||||
|
<property name="publishingRootObject" ref="publishingRootObject" />
|
||||||
|
<property name="dictionaryService" ref="DictionaryService" />
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
<property name="channelHelper" ref="channelHelper" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Channel Type Implementations -->
|
||||||
|
<bean id="baseChannelType" class="org.alfresco.repo.publishing.AbstractChannelType" abstract="true" >
|
||||||
|
<property name="channelService" ref="channelService" />
|
||||||
|
<property name="serviceRegistry" ref="ServiceRegistry" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="channelHelper" class="org.alfresco.repo.publishing.ChannelHelper">
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
<property name="dictionaryService" ref="DictionaryService" />
|
||||||
|
<property name="fileFolderService" ref="FileFolderService" />
|
||||||
|
<property name="permissionService" ref="PermissionService" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="publishingRootObject" class="org.alfresco.repo.publishing.PublishingRootObject">
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
<property name="namespaceService" ref="NamespaceService" />
|
||||||
|
<property name="searchService" ref="SearchService" />
|
||||||
|
<property name="publishingEventHelper" ref="publishingEventHelper" />
|
||||||
|
<property name="retryingTransactionHelper" ref="retryingTransactionHelper" />
|
||||||
|
<property name="permissionService" ref="PermissionService" />
|
||||||
|
<property name="publishingStore" value="${spaces.store}" />
|
||||||
|
<property name="publishingRootPath" value="${publishing.root}" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="publishingEventHelper" class="org.alfresco.repo.publishing.PublishingEventHelper">
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
<property name="contentService" ref="ContentService" />
|
||||||
|
<property name="serializer" ref="publishingPackageSerializer" />
|
||||||
|
<property name="workflowService" ref="WorkflowService" />
|
||||||
|
<property name="permissionService" ref="PermissionService" />
|
||||||
|
<property name="transferManifestNodeFactory" ref="transferManifestNodeFactory" />
|
||||||
|
<property name="versionService" ref="VersionService" />
|
||||||
|
<property name="workflowEngineId" value="activiti" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Publish Event Action -->
|
||||||
|
<bean id="pub_publishEvent" class="org.alfresco.repo.publishing.PublishEventAction" >
|
||||||
|
<property name="publishingEventProcessor" ref="publishingEventProcessor" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Publishing Event Processor -->
|
||||||
|
<bean id="publishingEventProcessor" class="org.alfresco.repo.publishing.PublishingEventProcessor">
|
||||||
|
<property name="channelHelper" ref="channelHelper" />
|
||||||
|
<property name="channelService" ref="channelService" />
|
||||||
|
<property name="publishingEventHelper" ref="publishingEventHelper" />
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
<property name="behaviourFilter" ref="policyBehaviourFilter" />
|
||||||
|
<property name="urlShortener" ref="urlShortener" />
|
||||||
|
<property name="dictionaryService" ref="DictionaryService" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Publishing Service -->
|
||||||
|
<bean id="publishingService" class="org.alfresco.repo.publishing.PublishServiceImpl">
|
||||||
|
<property name="publishingRootObject" ref="publishingRootObject" />
|
||||||
|
<property name="publishingEventHelper" ref="publishingEventHelper" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="publishingPackageSerializer" class="org.alfresco.repo.publishing.StandardNodeSnapshotSerializer" />
|
||||||
|
|
||||||
|
<bean id="urlShortener" class="org.alfresco.repo.urlshortening.BitlyUrlShortenerImpl" >
|
||||||
|
<property name="username" value="${urlshortening.bitly.username}" />
|
||||||
|
<property name="apiKey" value="${urlshortening.bitly.api.key}" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
</beans>
|
@@ -6,13 +6,19 @@
|
|||||||
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema"
|
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">
|
expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://alfresco.org">
|
||||||
|
|
||||||
<process id="activitiPublishWebContent" name="Publish Web Content Activiti Process">
|
<process id="publishWebContent" name="Publish Web Content Activiti Process">
|
||||||
|
|
||||||
<startEvent id="start"
|
<startEvent id="start"
|
||||||
activiti:formKey="pubwf:startPublish" />
|
activiti:formKey="pubwf:startPublish" />
|
||||||
|
|
||||||
<sequenceFlow id='flow1'
|
<sequenceFlow id='flow0'
|
||||||
sourceRef='start'
|
sourceRef='start'
|
||||||
|
targetRef='startWait' />
|
||||||
|
|
||||||
|
<receiveTask id="startWait" name="Receive event for start-task" />
|
||||||
|
|
||||||
|
<sequenceFlow id='flow1'
|
||||||
|
sourceRef='startWait'
|
||||||
targetRef='checkForScheduledTime'>
|
targetRef='checkForScheduledTime'>
|
||||||
<extensionElements>
|
<extensionElements>
|
||||||
<!-- If the schedule date is null, publish should be performed immediatly. Gateway used the 'schedule' boolean -->
|
<!-- If the schedule date is null, publish should be performed immediatly. Gateway used the 'schedule' boolean -->
|
||||||
@@ -20,7 +26,7 @@
|
|||||||
<activiti:field name="script">
|
<activiti:field name="script">
|
||||||
<activiti:string>
|
<activiti:string>
|
||||||
// Check if the publish should be scheduled or performed immediatly
|
// 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);
|
execution.setVariable("schedule", true);
|
||||||
} else {
|
} else {
|
||||||
execution.setVariable("schedule", false);
|
execution.setVariable("schedule", false);
|
||||||
@@ -39,7 +45,7 @@
|
|||||||
|
|
||||||
<exclusiveGateway id="checkForScheduledTime" name="Check Schedule" />
|
<exclusiveGateway id="checkForScheduledTime" name="Check Schedule" />
|
||||||
|
|
||||||
<sequenceFlow id='flow3' sourceRef='checkForScheduledTime' targetRef='schedulePublish' >
|
<sequenceFlow id='flow3' sourceRef='checkForScheduledTime' targetRef='waitForScheduledTime' >
|
||||||
<conditionExpression xsi:type="tFormalExpression">${schedule}</conditionExpression>
|
<conditionExpression xsi:type="tFormalExpression">${schedule}</conditionExpression>
|
||||||
</sequenceFlow>
|
</sequenceFlow>
|
||||||
|
|
||||||
@@ -60,15 +66,15 @@
|
|||||||
</extensionElements>
|
</extensionElements>
|
||||||
</serviceTask>
|
</serviceTask>
|
||||||
|
|
||||||
<receiveTask id="schedulePublish" name="Wait for publish time" />
|
<receiveTask id="waitForScheduledTime" name="Wait for publish time" />
|
||||||
|
|
||||||
<boundaryEvent id="publishTimer" cancelActivity="true" attachedToRef="schedulePublish">
|
<boundaryEvent id="publishTimer" cancelActivity="true" attachedToRef="waitForScheduledTime">
|
||||||
<timerEventDefinition>
|
<timerEventDefinition>
|
||||||
<timeDate>${iso8601PublishDate}</timeDate>
|
<timeDate>${iso8601PublishDate}</timeDate>
|
||||||
</timerEventDefinition>
|
</timerEventDefinition>
|
||||||
</boundaryEvent>
|
</boundaryEvent>
|
||||||
|
|
||||||
<sequenceFlow id='flow5' sourceRef='schedulePublish'
|
<sequenceFlow id='flow5' sourceRef='waitForScheduledTime'
|
||||||
targetRef='end' />
|
targetRef='end' />
|
||||||
|
|
||||||
<sequenceFlow id='flow6' sourceRef='publishTimer'
|
<sequenceFlow id='flow6' sourceRef='publishTimer'
|
||||||
|
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<WorkflowPath> paths = workflowService.getWorkflowPaths(instanceId);
|
||||||
|
assertEquals(2, paths.size());
|
||||||
|
WorkflowPath path = paths.get(0);
|
||||||
|
assertEquals(expNode, path.getNode().getName());
|
||||||
|
}
|
||||||
|
}
|
@@ -19,224 +19,21 @@
|
|||||||
|
|
||||||
package org.alfresco.repo.publishing;
|
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 Nick Smith
|
||||||
|
* @author Frederik Heremans
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class PublishWebContentJbpmTest extends BaseSpringTest
|
public class PublishWebContentJbpmTest extends PublishWebContentProcessTest
|
||||||
{
|
{
|
||||||
private static final String DEF_NAME = "jbpm$publishWebContent";
|
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<WorkflowPath> 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<Void> startWorkflowCallback = new RetryingTransactionCallback<Void>()
|
|
||||||
{
|
|
||||||
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<QName, Serializable> params = new HashMap<QName, Serializable>();
|
|
||||||
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<WorkflowPath> 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<Void>()
|
|
||||||
{
|
|
||||||
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<QName, Serializable> props = new HashMap<QName, Serializable>();
|
|
||||||
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
|
@Override
|
||||||
protected String[] getConfigLocations()
|
protected String getWorkflowDefinitionName()
|
||||||
{
|
{
|
||||||
return new String[]
|
return DEF_NAME;
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<WorkflowPath> 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<Void> startWorkflowCallback = new RetryingTransactionCallback<Void>()
|
||||||
|
{
|
||||||
|
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<QName, Serializable> params = new HashMap<QName, Serializable>();
|
||||||
|
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<WorkflowPath> 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<Void>()
|
||||||
|
{
|
||||||
|
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<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -132,7 +132,7 @@ public class PublishingQueueImplTest extends AbstractPublishingIntegrationTest
|
|||||||
WorkflowInstance instance = workflowService.getWorkflowById(wfId);
|
WorkflowInstance instance = workflowService.getWorkflowById(wfId);
|
||||||
assertNotNull(instance);
|
assertNotNull(instance);
|
||||||
List<WorkflowPath> paths = workflowService.getWorkflowPaths(wfId);
|
List<WorkflowPath> paths = workflowService.getWorkflowPaths(wfId);
|
||||||
assertEquals(1, paths.size());
|
assertEquals(2, paths.size());
|
||||||
Map<QName, Serializable> props = workflowService.getPathProperties(paths.get(0).getId());
|
Map<QName, Serializable> props = workflowService.getPathProperties(paths.get(0).getId());
|
||||||
assertEquals(eventNode, props.get(PROP_WF_PUBLISHING_EVENT));
|
assertEquals(eventNode, props.get(PROP_WF_PUBLISHING_EVENT));
|
||||||
assertEquals(schedule, props.get(PROP_WF_SCHEDULED_PUBLISH_DATE));
|
assertEquals(schedule, props.get(PROP_WF_SCHEDULED_PUBLISH_DATE));
|
||||||
|
@@ -46,6 +46,7 @@ import org.activiti.engine.history.HistoricProcessInstance;
|
|||||||
import org.activiti.engine.history.HistoricTaskInstance;
|
import org.activiti.engine.history.HistoricTaskInstance;
|
||||||
import org.activiti.engine.history.HistoricTaskInstanceQuery;
|
import org.activiti.engine.history.HistoricTaskInstanceQuery;
|
||||||
import org.activiti.engine.impl.RepositoryServiceImpl;
|
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.behavior.UserTaskActivityBehavior;
|
||||||
import org.activiti.engine.impl.bpmn.deployer.BpmnDeployer;
|
import org.activiti.engine.impl.bpmn.deployer.BpmnDeployer;
|
||||||
import org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator;
|
import org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator;
|
||||||
@@ -598,6 +599,16 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isReceiveTask(PvmActivity act)
|
||||||
|
{
|
||||||
|
if(act instanceof ActivityImpl)
|
||||||
|
{
|
||||||
|
ActivityImpl actImpl = (ActivityImpl) act;
|
||||||
|
return (actImpl.getActivityBehavior() instanceof ReceiveTaskActivityBehavior);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private Collection<PvmActivity> findUserTasks(PvmActivity startEvent)
|
private Collection<PvmActivity> findUserTasks(PvmActivity startEvent)
|
||||||
{
|
{
|
||||||
// Use a linked hashmap to get the task defs in the right order
|
// Use a linked hashmap to get the task defs in the right order
|
||||||
@@ -609,6 +620,17 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
|
|||||||
return userTasks.values();
|
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<String, PvmActivity> userTasks)
|
private void findUserTasks(PvmActivity currentActivity, Map<String, PvmActivity> userTasks)
|
||||||
{
|
{
|
||||||
// Only process activity if not already present to prevent endless loops
|
// Only process activity if not already present to prevent endless loops
|
||||||
@@ -974,10 +996,14 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
|
|||||||
|
|
||||||
// Start the process-instance
|
// Start the process-instance
|
||||||
ProcessInstance instance = runtimeService.startProcessInstanceById(processDefId, variables);
|
ProcessInstance instance = runtimeService.startProcessInstanceById(processDefId, variables);
|
||||||
|
if(instance.isEnded())
|
||||||
// Set ID of workflowinstance after ProcessInstance is created
|
{
|
||||||
runtimeService.setVariable(instance.getId(), WorkflowConstants.PROP_WORKFLOW_INSTANCE_ID, createGlobalId(instance.getId()));
|
return typeConverter.buildCompletedPath(instance.getId(), instance.getId());
|
||||||
return typeConverter.convert((Execution)instance);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return typeConverter.convert((Execution)instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (ActivitiException ae)
|
catch (ActivitiException ae)
|
||||||
{
|
{
|
||||||
@@ -1299,8 +1325,35 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
|
|||||||
// Set start task end date on the process
|
// Set start task end date on the process
|
||||||
runtimeService.setVariable(processInstanceId, ActivitiConstants.PROP_START_TASK_END_DATE, new Date());
|
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
|
// Check if the current activity is a signalTask and the first activity in the process,
|
||||||
return typeConverter.getVirtualStartTask(processInstanceId, false);
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.workflow.activiti;
|
package org.alfresco.repo.workflow.activiti;
|
||||||
|
|
||||||
|
import org.activiti.engine.delegate.ExecutionListener;
|
||||||
import org.activiti.engine.delegate.TaskListener;
|
import org.activiti.engine.delegate.TaskListener;
|
||||||
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
|
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
|
||||||
import org.activiti.engine.impl.bpmn.parser.BpmnParseListener;
|
import org.activiti.engine.impl.bpmn.parser.BpmnParseListener;
|
||||||
@@ -42,6 +43,7 @@ public class AddTaskListenerParseListener implements BpmnParseListener
|
|||||||
{
|
{
|
||||||
private TaskListener completeTaskListener;
|
private TaskListener completeTaskListener;
|
||||||
private TaskListener createTaskListener;
|
private TaskListener createTaskListener;
|
||||||
|
private ExecutionListener processCreateListener;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void parseUserTask(Element userTaskElement, ScopeImpl scope, ActivityImpl activity)
|
public void parseUserTask(Element userTaskElement, ScopeImpl scope, ActivityImpl activity)
|
||||||
@@ -64,7 +66,7 @@ public class AddTaskListenerParseListener implements BpmnParseListener
|
|||||||
@Override
|
@Override
|
||||||
public void parseProcess(Element processElement, ProcessDefinitionEntity processDefinition)
|
public void parseProcess(Element processElement, ProcessDefinitionEntity processDefinition)
|
||||||
{
|
{
|
||||||
// Nothing to do here
|
processDefinition.addExecutionListener(ExecutionListener.EVENTNAME_START, processCreateListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -197,4 +199,9 @@ public class AddTaskListenerParseListener implements BpmnParseListener
|
|||||||
this.createTaskListener = createTaskListener;
|
this.createTaskListener = createTaskListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setProcessCreateListener(ExecutionListener processCreateListener)
|
||||||
|
{
|
||||||
|
this.processCreateListener = processCreateListener;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package org.alfresco.repo.workflow.activiti.listener;
|
package org.alfresco.repo.workflow.activiti.listener;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.activiti.engine.delegate.DelegateExecution;
|
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");
|
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) {
|
if(dateToConvert != null) {
|
||||||
// Convert the date to ISO-8601 format
|
// Convert the date to ISO-8601 format
|
||||||
String convertedDate = ISO8601DateFormat.format(dateToConvert);
|
String convertedDate = ISO8601DateFormat.format(dateToConvert);
|
||||||
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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()));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user