提交 626761e0 编写于 作者: J Joram Barrez

(port of v5 commit...

(port of v5 commit https://github.com/Activiti/Activiti/commit/08a1fde0fe4cb3aa111bf0cef3ee902010925263) Introduced four new engine event types: historic process instance created/ended and historic activity created/ended, as an alternative to existing events.
The use case is similar to the default process started/ended and activity started/completed, but used the Historic entities which adds additional data (startUserId, duration, etc.).
Also fixed the historic activity instance creation for subprocess start events (were missing + had incorrect end time).
上级 8f235043
......@@ -16,6 +16,8 @@ import java.util.ArrayList;
import java.util.List;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.apache.commons.lang3.StringUtils;
/**
......@@ -132,6 +134,28 @@ public enum ActivitiEventType {
* {@link #ACTIVITY_COMPLETE} for the involved activity, if the error was delivered successfully.
*/
ACTIVITY_ERROR_RECEIVED,
/**
* A event dispatched when a {@link HistoricActivityInstance} is created.
* This is a specialized version of the {@link ActivitiEventType#ENTITY_CREATED} and {@link ActivitiEventType#ENTITY_INITIALIZED} event,
* with the same use case as the {@link ActivitiEventType#ACTIVITY_STARTED}, but containing
* slightly different data.
*
* Note this will be an {@link ActivitiEntityEvent}, where the entity is the {@link HistoricActivityInstance}.
*
* Note that history (minimum level ACTIVITY) must be enabled to receive this event.
*/
HISTORIC_ACTIVITY_INSTANCE_CREATED,
/**
* A event dispatched when a {@link HistoricActivityInstance} is marked as ended.
* his is a specialized version of the {@link ActivitiEventType#ENTITY_UPDATED} event,
* with the same use case as the {@link ActivitiEventType#ACTIVITY_COMPLETED}, but containing
* slightly different data (e.g. the end time, the duration, etc.).
*
* Note that history (minimum level ACTIVITY) must be enabled to receive this event.
*/
HISTORIC_ACTIVITY_INSTANCE_ENDED,
/**
* Indicates the engine has taken (ie. followed) a sequenceflow from a source activity to a target activity.
......@@ -196,6 +220,28 @@ public enum ActivitiEventType {
* @see org.activiti.engine.impl.RuntimeServiceImpl#deleteProcessInstance(java.lang.String, java.lang.String), before DB delete.
*/
PROCESS_CANCELLED,
/**
* A event dispatched when a {@link HistoricProcessInstance} is created.
* This is a specialized version of the {@link ActivitiEventType#ENTITY_CREATED} and {@link ActivitiEventType#ENTITY_INITIALIZED} event,
* with the same use case as the {@link ActivitiEventType#PROCESS_STARTED}, but containing
* slightly different data (e.g. the start time, the start user id, etc.).
*
* Note this will be an {@link ActivitiEntityEvent}, where the entity is the {@link HistoricProcessInstance}.
*
* Note that history (minimum level ACTIVITY) must be enabled to receive this event.
*/
HISTORIC_PROCESS_INSTANCE_CREATED,
/**
* A event dispatched when a {@link HistoricProcessInstance} is marked as ended.
* his is a specialized version of the {@link ActivitiEventType#ENTITY_UPDATED} event,
* with the same use case as the {@link ActivitiEventType#PROCESS_COMPLETED}, but containing
* slightly different data (e.g. the end time, the duration, etc.).
*
* Note that history (minimum level ACTIVITY) must be enabled to receive this event.
*/
HISTORIC_PROCESS_INSTANCE_ENDED,
/**
* A new membership has been created.
......
......@@ -27,7 +27,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;
......@@ -948,7 +947,7 @@ public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfig
properties.put("limitBetween", DbSqlSessionFactory.databaseSpecificLimitBetweenStatements.get(databaseType));
properties.put("limitOuterJoinBetween", DbSqlSessionFactory.databaseOuterJoinLimitBetweenStatements.get(databaseType));
properties.put("orderBy", DbSqlSessionFactory.databaseSpecificOrderByStatements.get(databaseType));
properties.put("limitBeforeNativeQuery", Objects.toString(DbSqlSessionFactory.databaseSpecificLimitBeforeNativeQueryStatements.get(databaseType)));
properties.put("limitBeforeNativeQuery", String.valueOf(DbSqlSessionFactory.databaseSpecificLimitBeforeNativeQueryStatements.get(databaseType)));
}
Configuration configuration = initMybatisConfiguration(environment, reader, properties);
......
......@@ -39,176 +39,183 @@ import com.fasterxml.jackson.databind.ObjectMapper;
* @author Joram Barrez
*/
public class EventLogger implements ActivitiEventListener {
private static final Logger logger = LoggerFactory.getLogger(EventLogger.class);
private static final String EVENT_FLUSHER_KEY = "eventFlusher";
protected Clock clock;
protected ObjectMapper objectMapper;
// Mapping of type -> handler
protected Map<ActivitiEventType, Class<? extends EventLoggerEventHandler>> eventHandlers = new HashMap<ActivitiEventType, Class<? extends EventLoggerEventHandler>>();
// Listeners for new events
protected List<EventLoggerListener> listeners;
public EventLogger(Clock clock, ObjectMapper objectMapper) {
this.clock = clock;
this.objectMapper = objectMapper;
// Initialization of all event handlers
addEventHandler(ActivitiEventType.TASK_CREATED, TaskCreatedEventHandler.class);
addEventHandler(ActivitiEventType.TASK_COMPLETED, TaskCompletedEventHandler.class);
addEventHandler(ActivitiEventType.TASK_ASSIGNED, TaskAssignedEventHandler.class);
addEventHandler(ActivitiEventType.SEQUENCEFLOW_TAKEN, SequenceFlowTakenEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_COMPLETED, ActivityCompletedEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_STARTED, ActivityStartedEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_SIGNALED, ActivitySignaledEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_MESSAGE_RECEIVED, ActivityMessageEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_COMPENSATE, ActivityCompensatedEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_ERROR_RECEIVED, ActivityErrorReceivedEventHandler.class);
addEventHandler(ActivitiEventType.VARIABLE_CREATED, VariableCreatedEventHandler.class);
addEventHandler(ActivitiEventType.VARIABLE_DELETED, VariableDeletedEventHandler.class);
addEventHandler(ActivitiEventType.VARIABLE_UPDATED, VariableUpdatedEventHandler.class);
private static final Logger logger = LoggerFactory.getLogger(EventLogger.class);
private static final String EVENT_FLUSHER_KEY = "eventFlusher";
protected Clock clock;
protected ObjectMapper objectMapper;
// Mapping of type -> handler
protected Map<ActivitiEventType, Class<? extends EventLoggerEventHandler>> eventHandlers
= new HashMap<ActivitiEventType, Class<? extends EventLoggerEventHandler>>();
// Listeners for new events
protected List<EventLoggerListener> listeners;
public EventLogger() {
initializeDefaultHandlers();
}
public EventLogger(Clock clock, ObjectMapper objectMapper) {
this();
this.clock = clock;
this.objectMapper = objectMapper;
}
protected void initializeDefaultHandlers() {
addEventHandler(ActivitiEventType.TASK_CREATED, TaskCreatedEventHandler.class);
addEventHandler(ActivitiEventType.TASK_COMPLETED, TaskCompletedEventHandler.class);
addEventHandler(ActivitiEventType.TASK_ASSIGNED, TaskAssignedEventHandler.class);
addEventHandler(ActivitiEventType.SEQUENCEFLOW_TAKEN, SequenceFlowTakenEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_COMPLETED, ActivityCompletedEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_STARTED, ActivityStartedEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_SIGNALED, ActivitySignaledEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_MESSAGE_RECEIVED, ActivityMessageEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_COMPENSATE, ActivityCompensatedEventHandler.class);
addEventHandler(ActivitiEventType.ACTIVITY_ERROR_RECEIVED, ActivityErrorReceivedEventHandler.class);
addEventHandler(ActivitiEventType.VARIABLE_CREATED, VariableCreatedEventHandler.class);
addEventHandler(ActivitiEventType.VARIABLE_DELETED, VariableDeletedEventHandler.class);
addEventHandler(ActivitiEventType.VARIABLE_UPDATED, VariableUpdatedEventHandler.class);
}
@Override
public void onEvent(ActivitiEvent event) {
EventLoggerEventHandler eventHandler = getEventHandler(event);
if (eventHandler != null) {
// Events are flushed when command context is closed
CommandContext currentCommandContext = Context.getCommandContext();
EventFlusher eventFlusher = (EventFlusher) currentCommandContext.getAttribute(EVENT_FLUSHER_KEY);
if (eventFlusher == null) {
eventFlusher = createEventFlusher();
if (eventFlusher == null) {
eventFlusher = new DatabaseEventFlusher(); // Default
}
currentCommandContext.addAttribute(EVENT_FLUSHER_KEY, eventFlusher);
currentCommandContext.addCloseListener(eventFlusher);
currentCommandContext.addCloseListener(new CommandContextCloseListener() {
@Override
public void closing(CommandContext commandContext) {
}
@Override
public void closed(CommandContext commandContext) {
// For those who are interested: we can now broadcast
// the events were added
if (listeners != null) {
for (EventLoggerListener listener : listeners) {
listener.eventsAdded(EventLogger.this);
}
}
}
});
}
eventFlusher.addEventHandler(eventHandler);
}
}
// Subclasses can override this if defaults are not ok
protected EventLoggerEventHandler getEventHandler(ActivitiEvent event) {
Class<? extends EventLoggerEventHandler> eventHandlerClass = null;
if (event.getType().equals(ActivitiEventType.ENTITY_INITIALIZED)) {
Object entity = ((ActivitiEntityEvent) event).getEntity();
if (entity instanceof ExecutionEntity) {
ExecutionEntity executionEntity = (ExecutionEntity) entity;
if (executionEntity.getProcessInstanceId().equals(executionEntity.getId())) {
eventHandlerClass = ProcessInstanceStartedEventHandler.class;
}
}
} else if (event.getType().equals(ActivitiEventType.ENTITY_DELETED)) {
Object entity = ((ActivitiEntityEvent) event).getEntity();
if (entity instanceof ExecutionEntity) {
ExecutionEntity executionEntity = (ExecutionEntity) entity;
if (executionEntity.getProcessInstanceId().equals(executionEntity.getId())) {
eventHandlerClass = ProcessInstanceEndedEventHandler.class;
}
}
} else {
// Default: dedicated mapper for the type
eventHandlerClass = eventHandlers.get(event.getType());
}
if (eventHandlerClass != null) {
return instantiateEventHandler(event, eventHandlerClass);
}
return null;
@Override
public void onEvent(ActivitiEvent event) {
EventLoggerEventHandler eventHandler = getEventHandler(event);
if (eventHandler != null) {
// Events are flushed when command context is closed
CommandContext currentCommandContext = Context.getCommandContext();
EventFlusher eventFlusher = (EventFlusher) currentCommandContext.getAttribute(EVENT_FLUSHER_KEY);
if (eventHandler != null && eventFlusher == null) {
eventFlusher = createEventFlusher();
if (eventFlusher == null) {
eventFlusher = new DatabaseEventFlusher(); // Default
}
currentCommandContext.addAttribute(EVENT_FLUSHER_KEY, eventFlusher);
currentCommandContext.addCloseListener(eventFlusher);
currentCommandContext
.addCloseListener(new CommandContextCloseListener() {
@Override
public void closing(CommandContext commandContext) {
}
@Override
public void closed(CommandContext commandContext) {
// For those who are interested: we can now broadcast the events were added
if (listeners != null) {
for (EventLoggerListener listener : listeners) {
listener.eventsAdded(EventLogger.this);
}
}
}
});
}
eventFlusher.addEventHandler(eventHandler);
}
}
// Subclasses can override this if defaults are not ok
protected EventLoggerEventHandler getEventHandler(ActivitiEvent event) {
Class<? extends EventLoggerEventHandler> eventHandlerClass = null;
if (event.getType().equals(ActivitiEventType.ENTITY_INITIALIZED)) {
Object entity = ((ActivitiEntityEvent) event).getEntity();
if (entity instanceof ExecutionEntity) {
ExecutionEntity executionEntity = (ExecutionEntity) entity;
if (executionEntity.getProcessInstanceId().equals(executionEntity.getId())) {
eventHandlerClass = ProcessInstanceStartedEventHandler.class;
}
}
} else if (event.getType().equals(ActivitiEventType.ENTITY_DELETED)) {
Object entity = ((ActivitiEntityEvent) event).getEntity();
if (entity instanceof ExecutionEntity) {
ExecutionEntity executionEntity = (ExecutionEntity) entity;
if (executionEntity.getProcessInstanceId().equals(executionEntity.getId())) {
eventHandlerClass = ProcessInstanceEndedEventHandler.class;
}
}
} else {
// Default: dedicated mapper for the type
eventHandlerClass = eventHandlers.get(event.getType());
}
if (eventHandlerClass != null) {
return instantiateEventHandler(event, eventHandlerClass);
}
return null;
}
protected EventLoggerEventHandler instantiateEventHandler(ActivitiEvent event,
Class<? extends EventLoggerEventHandler> eventHandlerClass) {
try {
EventLoggerEventHandler eventHandler = eventHandlerClass.newInstance();
eventHandler.setTimeStamp(clock.getCurrentTime());
eventHandler.setEvent(event);
eventHandler.setObjectMapper(objectMapper);
return eventHandler;
} catch (Exception e) {
logger.warn("Could not instantiate " + eventHandlerClass + ", this is most likely a programmatic error");
}
return null;
}
protected EventLoggerEventHandler instantiateEventHandler(ActivitiEvent event, Class<? extends EventLoggerEventHandler> eventHandlerClass) {
try {
EventLoggerEventHandler eventHandler = eventHandlerClass.newInstance();
eventHandler.setTimeStamp(clock.getCurrentTime());
eventHandler.setEvent(event);
eventHandler.setObjectMapper(objectMapper);
return eventHandler;
} catch (Exception e) {
logger.warn("Could not instantiate " + eventHandlerClass + ", this is most likely a programmatic error");
}
return null;
}
@Override
@Override
public boolean isFailOnException() {
return false;
}
public void addEventHandler(ActivitiEventType eventType, Class<? extends EventLoggerEventHandler> eventHandlerClass) {
eventHandlers.put(eventType, eventHandlerClass);
}
public void addEventLoggerListener(EventLoggerListener listener) {
if (listeners == null) {
listeners = new ArrayList<EventLoggerListener>(1);
}
listeners.add(listener);
}
/**
* Subclasses that want something else than the database flusher should override this method
*/
protected EventFlusher createEventFlusher() {
return null;
}
public Clock getClock() {
return clock;
}
public void setClock(Clock clock) {
this.clock = clock;
return false;
}
public ObjectMapper getObjectMapper() {
return objectMapper;
}
public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
public List<EventLoggerListener> getListeners() {
return listeners;
}
public void setListeners(List<EventLoggerListener> listeners) {
this.listeners = listeners;
}
public void addEventHandler(ActivitiEventType eventType, Class<? extends EventLoggerEventHandler> eventHandlerClass) {
eventHandlers.put(eventType, eventHandlerClass);
}
public void addEventLoggerListener(EventLoggerListener listener) {
if (listeners == null) {
listeners = new ArrayList<EventLoggerListener>(1);
}
listeners.add(listener);
}
/**
* Subclasses that want something else than the database flusher should override this method
*/
protected EventFlusher createEventFlusher() {
return null;
}
public Clock getClock() {
return clock;
}
public void setClock(Clock clock) {
this.clock = clock;
}
public ObjectMapper getObjectMapper() {
return objectMapper;
}
public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
public List<EventLoggerListener> getListeners() {
return listeners;
}
public void setListeners(List<EventLoggerListener> listeners) {
this.listeners = listeners;
}
}
......@@ -20,6 +20,9 @@ import java.util.Map;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.engine.delegate.event.ActivitiEventDispatcher;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.impl.cfg.IdGenerator;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.identity.Authentication;
......@@ -101,6 +104,14 @@ public class DefaultHistoryManager extends AbstractManager implements HistoryMan
if (historicProcessInstance != null) {
historicProcessInstance.markEnded(deleteReason);
historicProcessInstance.setEndActivityId(activityId);
// Fire event
ActivitiEventDispatcher activitiEventDispatcher = getEventDispatcher();
if (activitiEventDispatcher != null && activitiEventDispatcher.isEnabled()) {
activitiEventDispatcher.dispatchEvent(
ActivitiEventBuilder.createEntityEvent(ActivitiEventType.HISTORIC_PROCESS_INSTANCE_ENDED, historicProcessInstance));
}
}
}
}
......@@ -129,33 +140,14 @@ public class DefaultHistoryManager extends AbstractManager implements HistoryMan
// Insert historic process-instance
getHistoricProcessInstanceEntityManager().insert(historicProcessInstance, false);
// Fire event
ActivitiEventDispatcher activitiEventDispatcher = getEventDispatcher();
if (activitiEventDispatcher != null && activitiEventDispatcher.isEnabled()) {
activitiEventDispatcher.dispatchEvent(
ActivitiEventBuilder.createEntityEvent(ActivitiEventType.HISTORIC_PROCESS_INSTANCE_CREATED, historicProcessInstance));
}
// // Also record the start-event manually, as there is no "start"
// // activity history listener for this
// IdGenerator idGenerator = Context.getProcessEngineConfiguration().getIdGenerator();
//
// String processDefinitionId = processInstance.getProcessDefinitionId();
// String processInstanceId = processInstance.getId();
// String executionId = processInstance.getId();
// HistoricActivityInstanceEntity historicActivityInstance = new HistoricActivityInstanceEntity();
// historicActivityInstance.setId(idGenerator.getNextId());
// historicActivityInstance.setProcessDefinitionId(processDefinitionId);
// historicActivityInstance.setProcessInstanceId(processInstanceId);
// historicActivityInstance.setExecutionId(executionId);
// historicActivityInstance.setActivityId(startElement.getId());
// historicActivityInstance.setActivityName(startElement.getName());
// historicActivityInstance.setActivityType(parseActivityType(startElement));
// Date now = Context.getProcessEngineConfiguration().getClock().getCurrentTime();
// historicActivityInstance.setStartTime(now);
// historicActivityInstance.setEndTime(now);
//
// // Inherit tenant id (if applicable)
// if (processInstance.getTenantId() != null) {
// historicActivityInstance.setTenantId(processInstance.getTenantId());
// }
//
// getDbSqlSession().insert(historicActivityInstance);
}
}
......@@ -176,29 +168,19 @@ public class DefaultHistoryManager extends AbstractManager implements HistoryMan
historicProcessInstance.setStartActivityId(initialElement.getId());
}
getHistoricProcessInstanceEntityManager().insert(historicProcessInstance, false);
// Fire event
ActivitiEventDispatcher activitiEventDispatcher = getEventDispatcher();
if (activitiEventDispatcher != null && activitiEventDispatcher.isEnabled()) {
activitiEventDispatcher.dispatchEvent(
ActivitiEventBuilder.createEntityEvent(ActivitiEventType.HISTORIC_PROCESS_INSTANCE_CREATED, historicProcessInstance));
}
HistoricActivityInstanceEntity activitiyInstance = findActivityInstance(parentExecution, false, true);
if (activitiyInstance != null) {
activitiyInstance.setCalledProcessInstanceId(subProcessInstance.getProcessInstanceId());
}
// // Fix for ACT-1728: start-event not recorded for subprocesses
// IdGenerator idGenerator = Context.getProcessEngineConfiguration().getIdGenerator();
//
// // Also record the start-event manually, as there is no "start"
// // activity history listener for this
// HistoricActivityInstanceEntity historicActivityInstance = new HistoricActivityInstanceEntity();
// historicActivityInstance.setId(idGenerator.getNextId());
// historicActivityInstance.setProcessDefinitionId(subProcessInstance.getProcessDefinitionId());
// historicActivityInstance.setProcessInstanceId(subProcessInstance.getProcessInstanceId());
// historicActivityInstance.setExecutionId(subProcessInstance.getId());
// historicActivityInstance.setActivityId(initialElement.getId());
// historicActivityInstance.setActivityName(initialElement.getName());
// historicActivityInstance.setActivityType(parseActivityType(initialElement));
// Date now = Context.getProcessEngineConfiguration().getClock().getCurrentTime();
// historicActivityInstance.setStartTime(now);
//
// getDbSqlSession().insert(historicActivityInstance);
}
}
......@@ -214,11 +196,14 @@ public class DefaultHistoryManager extends AbstractManager implements HistoryMan
if (isHistoryLevelAtLeast(HistoryLevel.ACTIVITY)) {
if (executionEntity.getCurrentActivityId() != null && executionEntity.getCurrentFlowElement() != null) {
createHistoricActivityInstanceEntity(executionEntity);
// HistoricActivityInstanceEntity historicActivityInstanceEntity = findActivityInstance(executionEntity, false);
// if (historicActivityInstanceEntity == null) {
// createHistoricActivityInstanceEntity(executionEntity);
// }
HistoricActivityInstanceEntity historicActivityInstanceEntity = createHistoricActivityInstanceEntity(executionEntity);
// Fire event
ActivitiEventDispatcher activitiEventDispatcher = getEventDispatcher();
if (activitiEventDispatcher != null && activitiEventDispatcher.isEnabled()) {
activitiEventDispatcher.dispatchEvent(
ActivitiEventBuilder.createEntityEvent(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_CREATED, historicActivityInstanceEntity));
}
}
}
......@@ -235,6 +220,13 @@ public class DefaultHistoryManager extends AbstractManager implements HistoryMan
HistoricActivityInstanceEntity historicActivityInstance = findActivityInstance(executionEntity, false, true);
if (historicActivityInstance != null) {
historicActivityInstance.markEnded(null);
// Fire event
ActivitiEventDispatcher activitiEventDispatcher = getEventDispatcher();
if (activitiEventDispatcher != null && activitiEventDispatcher.isEnabled()) {
activitiEventDispatcher.dispatchEvent(
ActivitiEventBuilder.createEntityEvent(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_ENDED, historicActivityInstance));
}
}
}
}
......
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.activiti.engine.test.api.event;
import java.util.List;
import org.activiti.engine.delegate.event.ActivitiEntityEvent;
import org.activiti.engine.delegate.event.ActivitiEvent;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.history.HistoryLevel;
import org.activiti.engine.impl.test.PluggableActivitiTestCase;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.test.Deployment;
/**
* Test case for all {@link ActivitiEvent}s related to activities.
*
* @author Frederik Heremans
* @author Joram Barrez
*/
public class HistoricActivityEventsTest extends PluggableActivitiTestCase {
private TestHistoricActivityEventListener listener;
@Override
protected void setUp() throws Exception {
super.setUp();
this.listener = new TestHistoricActivityEventListener();
processEngineConfiguration.getEventDispatcher().addEventListener(listener);
}
@Override
protected void tearDown() throws Exception {
if (listener != null) {
listener.clearEventsReceived();
processEngineConfiguration.getEventDispatcher().removeEventListener(listener);
}
super.tearDown();
}
/**
* Test added to assert the historic activity instance event
*/
@Deployment
public void testHistoricActivityEventDispatched() {
if (processEngineConfiguration.getHistoryLevel().isAtLeast(HistoryLevel.ACTIVITY)) {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("TestActivityEvents");
assertNotNull(processInstance);
for (int i = 0; i < 2; i++) {
taskService.complete(taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult().getId());
}
List<ActivitiEvent> events = listener.getEventsReceived();
// Process instance start
assertEquals(ActivitiEventType.HISTORIC_PROCESS_INSTANCE_CREATED, events.get(0).getType());
// main start
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_CREATED, events.get(1).getType());
assertEquals("mainStart", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(1)).getEntity()).getActivityId()));
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_ENDED, events.get(2).getType());
assertEquals("mainStart", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(2)).getEntity()).getActivityId()));
assertNotNull("mainStart", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(2)).getEntity()).getEndTime()));
// Subprocess start
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_CREATED, events.get(3).getType());
assertEquals("subProcess", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(3)).getEntity()).getActivityId()));
// subProcessStart
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_CREATED, events.get(4).getType());
assertEquals("subProcessStart", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(4)).getEntity()).getActivityId()));
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_ENDED, events.get(5).getType());
assertEquals("subProcessStart", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(5)).getEntity()).getActivityId()));
assertNotNull("subProcessStart", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(5)).getEntity()).getEndTime()));
// Task a
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_CREATED, events.get(6).getType());
assertEquals("a", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(6)).getEntity()).getActivityId()));
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_ENDED, events.get(7).getType());
assertEquals("a", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(7)).getEntity()).getActivityId()));
assertNotNull("a", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(7)).getEntity()).getEndTime()));
// Task b
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_CREATED, events.get(8).getType());
assertEquals("b", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(8)).getEntity()).getActivityId()));
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_ENDED, events.get(9).getType());
assertEquals("b", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(9)).getEntity()).getActivityId()));
assertNotNull("b", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(9)).getEntity()).getEndTime()));
// subProcessEnd
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_CREATED, events.get(10).getType());
assertEquals("subprocessEnd", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(10)).getEntity()).getActivityId()));
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_ENDED, events.get(11).getType());
assertEquals("subprocessEnd", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(11)).getEntity()).getActivityId()));
assertNotNull("subprocessEnd", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(11)).getEntity()).getEndTime()));
// subProcess end
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_ENDED, events.get(12).getType());
assertEquals("subProcess", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(12)).getEntity()).getActivityId()));
assertNotNull("subProcess", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(12)).getEntity()).getEndTime()));
// main end
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_CREATED, events.get(13).getType());
assertEquals("mainEnd", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(13)).getEntity()).getActivityId()));
assertEquals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_ENDED, events.get(14).getType());
assertEquals("mainEnd", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(14)).getEntity()).getActivityId()));
assertNotNull("mainEnd", (((HistoricActivityInstance) ((ActivitiEntityEvent) events.get(14)).getEntity()).getEndTime()));
// Process instance end
assertEquals(ActivitiEventType.HISTORIC_PROCESS_INSTANCE_ENDED, events.get(15).getType());
}
}
}
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.activiti.engine.test.api.event;
import java.util.ArrayList;
import java.util.List;
import org.activiti.engine.delegate.event.ActivitiEvent;
import org.activiti.engine.delegate.event.ActivitiEventListener;
import org.activiti.engine.delegate.event.ActivitiEventType;
/**
* @author Joram Barrez
*/
public class TestHistoricActivityEventListener implements ActivitiEventListener {
private List<ActivitiEvent> eventsReceived;
public TestHistoricActivityEventListener() {
eventsReceived = new ArrayList<ActivitiEvent>();
}
public List<ActivitiEvent> getEventsReceived() {
return eventsReceived;
}
public void clearEventsReceived() {
eventsReceived.clear();
}
@Override
public void onEvent(ActivitiEvent event) {
if (event.getType().equals(ActivitiEventType.HISTORIC_PROCESS_INSTANCE_CREATED)
|| event.getType().equals(ActivitiEventType.HISTORIC_PROCESS_INSTANCE_ENDED)
|| event.getType().equals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_CREATED)
|| event.getType().equals(ActivitiEventType.HISTORIC_ACTIVITY_INSTANCE_ENDED)) {
eventsReceived.add(event);
}
}
@Override
public boolean isFailOnException() {
return false;
}
}
......@@ -13,12 +13,12 @@
package org.activiti.engine.test.bpmn.deployment;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.activiti.engine.impl.bpmn.deployer.ParsedDeployment;
......@@ -62,7 +62,7 @@ public class ParsedDeploymentTest extends PluggableActivitiTestCase {
Context.removeCommandContext();
}
public void testCreateAndQuery() {
public void testCreateAndQuery() throws UnsupportedEncodingException {
DeploymentEntity entity = assembleUnpersistedDeploymentEntity();
ParsedDeploymentBuilderFactory builderFactory = processEngineConfiguration.getParsedDeploymentBuilderFactory();
......@@ -101,17 +101,17 @@ public class ParsedDeploymentTest extends PluggableActivitiTestCase {
return null;
}
private DeploymentEntity assembleUnpersistedDeploymentEntity() {
private DeploymentEntity assembleUnpersistedDeploymentEntity() throws UnsupportedEncodingException {
DeploymentEntity entity = new DeploymentEntityImpl();
entity.addResource(buildResource(IDR_XML_NAME, IDR_PROCESS_XML));
entity.addResource(buildResource(EN_XML_NAME, EN_PROCESS_XML));
return entity;
}
private ResourceEntity buildResource(String name, String text) {
private ResourceEntity buildResource(String name, String text) throws UnsupportedEncodingException {
ResourceEntityImpl result = new ResourceEntityImpl();
result.setName(name);
result.setBytes(text.getBytes(UTF_8));
result.setBytes(text.getBytes("UTF8"));
return result;
}
......
<?xml version='1.0' encoding='UTF-8'?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" 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://www.activiti.org/processdef" xmlns:modeler="http://activiti.com/modeler" modeler:version="1.0en" modeler:exportDateTime="20151130153322538" modeler:modelId="969407" modeler:modelVersion="1" modeler:modelLastUpdated="1448897599772">
<process id="TestActivityEvents" name="TestActivityEvents" isExecutable="true">
<startEvent id="mainStart"/>
<subProcess id="subProcess" name="subProcess">
<startEvent id="subProcessStart"/>
<userTask id="a" name="A" activiti:assignee="$INITIATOR">
<extensionElements>
<modeler:allow-send-email>true</modeler:allow-send-email>
<modeler:activiti-idm-initiator>true</modeler:activiti-idm-initiator>
</extensionElements>
</userTask>
<userTask id="b" name="B" activiti:assignee="$INITIATOR">
<extensionElements>
<modeler:allow-send-email>true</modeler:allow-send-email>
<modeler:activiti-idm-initiator>true</modeler:activiti-idm-initiator>
</extensionElements>
</userTask>
<endEvent id="subprocessEnd"/>
<sequenceFlow id="sid-526B9ABC-0A00-4AA9-9B50-3AFBFC437D4A" sourceRef="subProcessStart" targetRef="a"/>
<sequenceFlow id="sid-34DFE08F-4298-4978-8C4F-A96E86E4BABA" sourceRef="a" targetRef="b"/>
<sequenceFlow id="sid-C347A793-B233-4B73-9B11-8D2639EC8C27" sourceRef="b" targetRef="subprocessEnd"/>
</subProcess>
<sequenceFlow id="sid-F5E7D48E-F284-4F6E-915B-CDA3F5EE85CA" sourceRef="mainStart" targetRef="subProcess"/>
<endEvent id="mainEnd"/>
<sequenceFlow id="sid-7ED65E92-1F62-4B42-9DA5-081F769ACE40" sourceRef="subProcess" targetRef="mainEnd"/>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_TestActivityEvents">
<bpmndi:BPMNPlane bpmnElement="TestActivityEvents" id="BPMNPlane_TestActivityEvents">
<bpmndi:BPMNShape bpmnElement="mainStart" id="BPMNShape_mainStart">
<omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="subProcess" id="BPMNShape_subProcess">
<omgdc:Bounds height="180.0" width="513.0" x="195.0" y="98.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="subProcessStart" id="BPMNShape_subProcessStart">
<omgdc:Bounds height="30.0" width="30.0" x="240.0" y="163.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="a" id="BPMNShape_a">
<omgdc:Bounds height="80.0" width="100.0" x="315.0" y="138.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="b" id="BPMNShape_b">
<omgdc:Bounds height="80.0" width="100.0" x="460.0" y="138.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="subprocessEnd" id="BPMNShape_subprocessEnd">
<omgdc:Bounds height="28.0" width="28.0" x="605.0" y="164.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="mainEnd" id="BPMNShape_mainEnd">
<omgdc:Bounds height="28.0" width="28.0" x="753.0" y="174.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sid-7ED65E92-1F62-4B42-9DA5-081F769ACE40" id="BPMNEdge_sid-7ED65E92-1F62-4B42-9DA5-081F769ACE40">
<omgdi:waypoint x="708.0" y="188.0"/>
<omgdi:waypoint x="753.0" y="188.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-F5E7D48E-F284-4F6E-915B-CDA3F5EE85CA" id="BPMNEdge_sid-F5E7D48E-F284-4F6E-915B-CDA3F5EE85CA">
<omgdi:waypoint x="129.99338082923626" y="178.44556852390002"/>
<omgdi:waypoint x="195.0" y="180.37741456166418"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-C347A793-B233-4B73-9B11-8D2639EC8C27" id="BPMNEdge_sid-C347A793-B233-4B73-9B11-8D2639EC8C27">
<omgdi:waypoint x="560.0" y="178.0"/>
<omgdi:waypoint x="605.0" y="178.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-526B9ABC-0A00-4AA9-9B50-3AFBFC437D4A" id="BPMNEdge_sid-526B9ABC-0A00-4AA9-9B50-3AFBFC437D4A">
<omgdi:waypoint x="270.0" y="178.0"/>
<omgdi:waypoint x="315.0" y="178.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-34DFE08F-4298-4978-8C4F-A96E86E4BABA" id="BPMNEdge_sid-34DFE08F-4298-4978-8C4F-A96E86E4BABA">
<omgdi:waypoint x="415.0" y="178.0"/>
<omgdi:waypoint x="460.0" y="178.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册