Loading src/main/java/com/inteligr8/activiti/mq/ActivitiEntityEventListener.java 0 → 100644 +69 −0 Original line number Diff line number Diff line package com.inteligr8.activiti.mq; import org.activiti.engine.delegate.event.ActivitiEntityEvent; import org.activiti.engine.delegate.event.ActivitiEventType; import org.activiti.engine.impl.persistence.entity.Entity; public interface ActivitiEntityEventListener<T extends Entity> { /** * This method checks to see if this listener is for the specified entity. * * @param entity An Activiti entity. * @return `true` if this listener supports the entity; `false` otherwise. */ default boolean ofEntityType(Entity entity) { return entity == null ? false : this.ofEntityType(entity.getClass()); } /** * This method checks to see if this listener is for the specified entity * class. * * @param entityType An Activiti entity class. * @return `true` if this listener supports the entity type; `false` otherwise. */ boolean ofEntityType(Class<? extends Entity> entityType); /** * This method allows for initialization on application startup. Any * resources this listener should subscribe to, should be connected or * opened. */ default void onApplicationStartup() { } /** * This method allows for uninitialization on application shutdown. Any * resources this listener subscribes to should be disconnected or closed. * * The `ActivitiEntityEventListener#onEvent()` method may still be called * before startup or after shutdown. */ default void onApplicationShutdown() { } /** * This method is fired every time there is a qualifying entity event. * * @param aaevent An Activiti entity event. */ default void onEntityEvent(ActivitiEntityEvent aaevent) { @SuppressWarnings("unchecked") T entity = (T) aaevent.getEntity(); this.onEntityEvent(aaevent.getType(), aaevent.getProcessDefinitionId(), aaevent.getProcessInstanceId(), aaevent.getExecutionId(), entity); } /** * Thi smethod is fired every time there is a qualifying entity event. * * @param eventType An Activiti event type; limited to `ENTITY_*`. * @param processDefinitionId The unique identifier of the process definition subject to the event. * @param processInstanceId The unique identifier of the process instance subject to the event. * @param executionId The unique identifier of the execution subject to the event. * @param entity The Activiti entity. */ void onEntityEvent(ActivitiEventType eventType, String processDefinitionId, String processInstanceId, String executionId, T entity); } src/main/java/com/inteligr8/activiti/mq/ActivitiEntityEventMonitor.java 0 → 100644 +111 −0 Original line number Diff line number Diff line package com.inteligr8.activiti.mq; import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.activiti.engine.ProcessEngine; import org.activiti.engine.delegate.event.ActivitiEntityEvent; import org.activiti.engine.delegate.event.ActivitiEvent; import org.activiti.engine.delegate.event.ActivitiEventListener; import org.activiti.engine.delegate.event.ActivitiEventType; import org.activiti.engine.impl.persistence.entity.Entity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ApplicationContextEvent; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextStartedEvent; import org.springframework.context.event.ContextStoppedEvent; import org.springframework.stereotype.Component; @Component public class ActivitiEntityEventMonitor implements ActivitiEventListener, ApplicationListener<ApplicationContextEvent> { private final Logger logger = LoggerFactory.getLogger(ActivitiEntityEventMonitor.class); @Autowired private List<ActivitiEntityEventListener<? extends Entity>> listeners; @Autowired private ProcessEngine services; /** * This method is fired by Spring, the framework behind Activiti. This * forwards the application event to each listener so they can initialize * or uninitialize. */ @Override public void onApplicationEvent(ApplicationContextEvent event) { if (event instanceof ContextRefreshedEvent || event instanceof ContextStoppedEvent || event instanceof ContextClosedEvent) { this.logger.debug("Application context refresh/stop/close detected; shutting down listeners: {}", event); for (ActivitiEntityEventListener<? extends Entity> listener : this.listeners) { listener.onApplicationShutdown(); } } // the listener cannot be active until the context is initialized if (event instanceof ContextRefreshedEvent || event instanceof ContextStartedEvent) { this.logger.debug("Application context refresh/start detected; starting up listeners: {}", event); for (ActivitiEntityEventListener<? extends Entity> listener : this.listeners) { listener.onApplicationStartup(); } } } /** * This method will start monitoring for changes in deployment, app, and * process definitions. */ @PostConstruct protected void init() { this.logger.debug("Bean initialized; starting to listen for any entity event ..."); this.services.getRuntimeService().addEventListener(this, ActivitiEventType.ENTITY_CREATED, ActivitiEventType.ENTITY_INITIALIZED, ActivitiEventType.ENTITY_UPDATED, ActivitiEventType.ENTITY_ACTIVATED, ActivitiEventType.ENTITY_SUSPENDED, ActivitiEventType.ENTITY_DELETED); } /** * This method will stop monitoring for changes in deployment, app, and * process definitions. */ @PreDestroy protected void uninit() { this.logger.debug("Bean uninitialized; stopping listener for any entity event ..."); this.services.getRuntimeService().removeEventListener(this); } /** * This method is fired by the Activiti platform. It is called on every * entity event. * * @param event An Activiti event. */ @Override public void onEvent(ActivitiEvent event) { this.logger.trace("Triggered by event: {}", event); for (ActivitiEntityEventListener<? extends Entity> listener : this.listeners) { ActivitiEntityEvent aaevent = (ActivitiEntityEvent) event; if (listener.ofEntityType((Entity) aaevent.getEntity())) listener.onEntityEvent(aaevent); } } @Override public boolean isFailOnException() { return true; } } src/main/java/com/inteligr8/activiti/mq/MQProcessDefinitionMonitor.javadeleted 100644 → 0 +0 −473 File deleted.Preview size limit exceeded, changes collapsed. Show changes src/main/java/com/inteligr8/activiti/mq/MqDeploymentEventListener.java 0 → 100644 +85 −0 Original line number Diff line number Diff line package com.inteligr8.activiti.mq; import java.util.List; import java.util.Set; import org.activiti.engine.delegate.event.ActivitiEventType; import org.activiti.engine.impl.persistence.entity.DeploymentEntity; import org.activiti.engine.impl.persistence.entity.Entity; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class MqDeploymentEventListener implements ActivitiEntityEventListener<DeploymentEntity> { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired protected MqSubscribeLooper looper; @Autowired protected ProcessDefinitionRegistry registry; @Autowired private MqSubscriptionService subscriptionService; @Override public boolean ofEntityType(Class<? extends Entity> entityType) { return DeploymentEntity.class.isAssignableFrom(entityType); } @Override public boolean ofEntityType(Entity entity) { return entity instanceof DeploymentEntity; } @Override public void onEntityEvent(ActivitiEventType eventType, String processDefinitionId, String processInstanceId, String executionId, DeploymentEntity entity) { this.logger.trace("Triggered by deployment event: {}", entity); switch (eventType) { case ENTITY_INITIALIZED: // we cannot use the ProcessDefinitionEntity for ENTITY_INITIALIZED as we need the BpmnModel later and it is not yet cached // we must use DeploymentEntity and then dig down for the process definitions this.onDeploymentAddEvent((DeploymentEntity) entity); break; default: } } protected void onDeploymentAddEvent(DeploymentEntity entity) { this.logger.debug("Triggered by deployment addition: {}", entity); List<ProcessDefinitionEntity> procDefEntities = entity.getDeployedArtifacts(ProcessDefinitionEntity.class); if (procDefEntities == null) return; this.logger.debug("Found {} process definitions in deployment: {}", procDefEntities.size(), entity.getId()); for (ProcessDefinitionEntity procDefEntity : procDefEntities) { this.logger.debug("Inspecting process definition: {}: {}: {}", procDefEntity.getId(), procDefEntity.getKey(), procDefEntity.getName()); this.unsubscribeOtherMqSubscribeTasks(procDefEntity.getId()); if (this.registry.isMqStart(procDefEntity.getId())) this.looper.loop(procDefEntity.getId()); } } protected void unsubscribeOtherMqSubscribeTasks(String procDefId) { try { Set<String> executionIds = this.subscriptionService.cancelAllOtherVersions(procDefId); if (this.logger.isDebugEnabled()) { this.logger.debug("Subscription executions ended early: {}: {}", procDefId, executionIds); } else { this.logger.info("Subscriptions ended early: {}: {}", procDefId, executionIds.size()); } } catch (Exception e) { this.logger.error("The subscriptions could not be cancelled: " + procDefId, e); } } } src/main/java/com/inteligr8/activiti/mq/MqExecutionService.java +72 −17 Original line number Diff line number Diff line Loading @@ -130,18 +130,74 @@ public class MqExecutionService { return this.cancelled(job.getExecutionId()); } /** * This method cancels all the executions active on the specified process * definition. * * @param executionId An execution unique identifier. * @return `true` if execution was cached; `false` otherwise. */ public boolean cancel(String executionId) throws Exception { Execution execution = this.services.getRuntimeService().createExecutionQuery().executionId(executionId).singleResult(); ProcessInstance pi = this.services.getRuntimeService().createProcessInstanceQuery().processInstanceId(execution.getProcessInstanceId()).singleResult(); return this.cancel(pi.getProcessDefinitionId(), executionId); } /** * This method cancels all the executions active on the specified process * definition. * * @param processDefinitionId A process definition unique identifier. * @return A set of execution identifiers that were cancelled. */ public Set<String> cancelAll(String processDefinitionId) throws Exception { ProcessDefinition processDefinition = this.services.getRepositoryService().getProcessDefinition(processDefinitionId); String processDefinitionKey = processDefinition.getKey(); return this.cancelAll(processDefinitionId, processDefinitionKey); } /** * @param latestProcessDefinitionId A process definition identifier to NOT clear. All other versions will be cleared. * @return A set of execution identifiers that were in the now cleared map. */ public synchronized Set<String> clearOtherVersions(String latestProcessDefinitionId) throws Exception { public synchronized Set<String> cancelAllOtherVersions(String latestProcessDefinitionId) throws Exception { ProcessDefinition latestProcessDefinition = this.services.getRepositoryService().getProcessDefinition(latestProcessDefinitionId); String processDefinitionKey = latestProcessDefinition.getKey(); Set<String> executionIds = new HashSet<>(); Collection<String> processDefinitionIds = this.processDefinitionKeyMap.get(processDefinitionKey); for (String processDefinitionId : processDefinitionIds) { for (String processDefinitionId : processDefinitionIds) executionIds.addAll(this.cancelAll(processDefinitionId, processDefinitionKey)); return executionIds; } private synchronized boolean cancel(String processDefinitionId, String executionId) throws Exception { this.logger.trace("Cancelling execution: {}: {}", processDefinitionId, executionId); Collection<String> activityIds = this.processDefinitionActivityMap.remove(processDefinitionId); if (activityIds == null) { this.logger.debug("No activities/executions to clear for process definition: {}", processDefinitionId); return false; } for (String activityId : activityIds) { this.logger.trace("Clearing process definition activity: {}: {}", processDefinitionId, activityId); Pair<String, String> key = this.toKey(processDefinitionId, activityId); Collection<String> activityExecutionIds = this.activityExecutionMap.get(key); if (activityExecutionIds.remove(executionId)) return true; } return false; } private synchronized Set<String> cancelAll(String processDefinitionId, String processDefinitionKey) throws Exception { Set<String> executionIds = new HashSet<>(); this.processDefinitionKeyMap.removeMapping(processDefinitionKey, processDefinitionId); Collection<String> activityIds = this.processDefinitionActivityMap.remove(processDefinitionId); Loading @@ -157,7 +213,6 @@ public class MqExecutionService { if (activityExecutionIds != null) executionIds.addAll(activityExecutionIds); } } return executionIds; } Loading Loading
src/main/java/com/inteligr8/activiti/mq/ActivitiEntityEventListener.java 0 → 100644 +69 −0 Original line number Diff line number Diff line package com.inteligr8.activiti.mq; import org.activiti.engine.delegate.event.ActivitiEntityEvent; import org.activiti.engine.delegate.event.ActivitiEventType; import org.activiti.engine.impl.persistence.entity.Entity; public interface ActivitiEntityEventListener<T extends Entity> { /** * This method checks to see if this listener is for the specified entity. * * @param entity An Activiti entity. * @return `true` if this listener supports the entity; `false` otherwise. */ default boolean ofEntityType(Entity entity) { return entity == null ? false : this.ofEntityType(entity.getClass()); } /** * This method checks to see if this listener is for the specified entity * class. * * @param entityType An Activiti entity class. * @return `true` if this listener supports the entity type; `false` otherwise. */ boolean ofEntityType(Class<? extends Entity> entityType); /** * This method allows for initialization on application startup. Any * resources this listener should subscribe to, should be connected or * opened. */ default void onApplicationStartup() { } /** * This method allows for uninitialization on application shutdown. Any * resources this listener subscribes to should be disconnected or closed. * * The `ActivitiEntityEventListener#onEvent()` method may still be called * before startup or after shutdown. */ default void onApplicationShutdown() { } /** * This method is fired every time there is a qualifying entity event. * * @param aaevent An Activiti entity event. */ default void onEntityEvent(ActivitiEntityEvent aaevent) { @SuppressWarnings("unchecked") T entity = (T) aaevent.getEntity(); this.onEntityEvent(aaevent.getType(), aaevent.getProcessDefinitionId(), aaevent.getProcessInstanceId(), aaevent.getExecutionId(), entity); } /** * Thi smethod is fired every time there is a qualifying entity event. * * @param eventType An Activiti event type; limited to `ENTITY_*`. * @param processDefinitionId The unique identifier of the process definition subject to the event. * @param processInstanceId The unique identifier of the process instance subject to the event. * @param executionId The unique identifier of the execution subject to the event. * @param entity The Activiti entity. */ void onEntityEvent(ActivitiEventType eventType, String processDefinitionId, String processInstanceId, String executionId, T entity); }
src/main/java/com/inteligr8/activiti/mq/ActivitiEntityEventMonitor.java 0 → 100644 +111 −0 Original line number Diff line number Diff line package com.inteligr8.activiti.mq; import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.activiti.engine.ProcessEngine; import org.activiti.engine.delegate.event.ActivitiEntityEvent; import org.activiti.engine.delegate.event.ActivitiEvent; import org.activiti.engine.delegate.event.ActivitiEventListener; import org.activiti.engine.delegate.event.ActivitiEventType; import org.activiti.engine.impl.persistence.entity.Entity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ApplicationContextEvent; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextStartedEvent; import org.springframework.context.event.ContextStoppedEvent; import org.springframework.stereotype.Component; @Component public class ActivitiEntityEventMonitor implements ActivitiEventListener, ApplicationListener<ApplicationContextEvent> { private final Logger logger = LoggerFactory.getLogger(ActivitiEntityEventMonitor.class); @Autowired private List<ActivitiEntityEventListener<? extends Entity>> listeners; @Autowired private ProcessEngine services; /** * This method is fired by Spring, the framework behind Activiti. This * forwards the application event to each listener so they can initialize * or uninitialize. */ @Override public void onApplicationEvent(ApplicationContextEvent event) { if (event instanceof ContextRefreshedEvent || event instanceof ContextStoppedEvent || event instanceof ContextClosedEvent) { this.logger.debug("Application context refresh/stop/close detected; shutting down listeners: {}", event); for (ActivitiEntityEventListener<? extends Entity> listener : this.listeners) { listener.onApplicationShutdown(); } } // the listener cannot be active until the context is initialized if (event instanceof ContextRefreshedEvent || event instanceof ContextStartedEvent) { this.logger.debug("Application context refresh/start detected; starting up listeners: {}", event); for (ActivitiEntityEventListener<? extends Entity> listener : this.listeners) { listener.onApplicationStartup(); } } } /** * This method will start monitoring for changes in deployment, app, and * process definitions. */ @PostConstruct protected void init() { this.logger.debug("Bean initialized; starting to listen for any entity event ..."); this.services.getRuntimeService().addEventListener(this, ActivitiEventType.ENTITY_CREATED, ActivitiEventType.ENTITY_INITIALIZED, ActivitiEventType.ENTITY_UPDATED, ActivitiEventType.ENTITY_ACTIVATED, ActivitiEventType.ENTITY_SUSPENDED, ActivitiEventType.ENTITY_DELETED); } /** * This method will stop monitoring for changes in deployment, app, and * process definitions. */ @PreDestroy protected void uninit() { this.logger.debug("Bean uninitialized; stopping listener for any entity event ..."); this.services.getRuntimeService().removeEventListener(this); } /** * This method is fired by the Activiti platform. It is called on every * entity event. * * @param event An Activiti event. */ @Override public void onEvent(ActivitiEvent event) { this.logger.trace("Triggered by event: {}", event); for (ActivitiEntityEventListener<? extends Entity> listener : this.listeners) { ActivitiEntityEvent aaevent = (ActivitiEntityEvent) event; if (listener.ofEntityType((Entity) aaevent.getEntity())) listener.onEntityEvent(aaevent); } } @Override public boolean isFailOnException() { return true; } }
src/main/java/com/inteligr8/activiti/mq/MQProcessDefinitionMonitor.javadeleted 100644 → 0 +0 −473 File deleted.Preview size limit exceeded, changes collapsed. Show changes
src/main/java/com/inteligr8/activiti/mq/MqDeploymentEventListener.java 0 → 100644 +85 −0 Original line number Diff line number Diff line package com.inteligr8.activiti.mq; import java.util.List; import java.util.Set; import org.activiti.engine.delegate.event.ActivitiEventType; import org.activiti.engine.impl.persistence.entity.DeploymentEntity; import org.activiti.engine.impl.persistence.entity.Entity; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class MqDeploymentEventListener implements ActivitiEntityEventListener<DeploymentEntity> { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired protected MqSubscribeLooper looper; @Autowired protected ProcessDefinitionRegistry registry; @Autowired private MqSubscriptionService subscriptionService; @Override public boolean ofEntityType(Class<? extends Entity> entityType) { return DeploymentEntity.class.isAssignableFrom(entityType); } @Override public boolean ofEntityType(Entity entity) { return entity instanceof DeploymentEntity; } @Override public void onEntityEvent(ActivitiEventType eventType, String processDefinitionId, String processInstanceId, String executionId, DeploymentEntity entity) { this.logger.trace("Triggered by deployment event: {}", entity); switch (eventType) { case ENTITY_INITIALIZED: // we cannot use the ProcessDefinitionEntity for ENTITY_INITIALIZED as we need the BpmnModel later and it is not yet cached // we must use DeploymentEntity and then dig down for the process definitions this.onDeploymentAddEvent((DeploymentEntity) entity); break; default: } } protected void onDeploymentAddEvent(DeploymentEntity entity) { this.logger.debug("Triggered by deployment addition: {}", entity); List<ProcessDefinitionEntity> procDefEntities = entity.getDeployedArtifacts(ProcessDefinitionEntity.class); if (procDefEntities == null) return; this.logger.debug("Found {} process definitions in deployment: {}", procDefEntities.size(), entity.getId()); for (ProcessDefinitionEntity procDefEntity : procDefEntities) { this.logger.debug("Inspecting process definition: {}: {}: {}", procDefEntity.getId(), procDefEntity.getKey(), procDefEntity.getName()); this.unsubscribeOtherMqSubscribeTasks(procDefEntity.getId()); if (this.registry.isMqStart(procDefEntity.getId())) this.looper.loop(procDefEntity.getId()); } } protected void unsubscribeOtherMqSubscribeTasks(String procDefId) { try { Set<String> executionIds = this.subscriptionService.cancelAllOtherVersions(procDefId); if (this.logger.isDebugEnabled()) { this.logger.debug("Subscription executions ended early: {}: {}", procDefId, executionIds); } else { this.logger.info("Subscriptions ended early: {}: {}", procDefId, executionIds.size()); } } catch (Exception e) { this.logger.error("The subscriptions could not be cancelled: " + procDefId, e); } } }
src/main/java/com/inteligr8/activiti/mq/MqExecutionService.java +72 −17 Original line number Diff line number Diff line Loading @@ -130,18 +130,74 @@ public class MqExecutionService { return this.cancelled(job.getExecutionId()); } /** * This method cancels all the executions active on the specified process * definition. * * @param executionId An execution unique identifier. * @return `true` if execution was cached; `false` otherwise. */ public boolean cancel(String executionId) throws Exception { Execution execution = this.services.getRuntimeService().createExecutionQuery().executionId(executionId).singleResult(); ProcessInstance pi = this.services.getRuntimeService().createProcessInstanceQuery().processInstanceId(execution.getProcessInstanceId()).singleResult(); return this.cancel(pi.getProcessDefinitionId(), executionId); } /** * This method cancels all the executions active on the specified process * definition. * * @param processDefinitionId A process definition unique identifier. * @return A set of execution identifiers that were cancelled. */ public Set<String> cancelAll(String processDefinitionId) throws Exception { ProcessDefinition processDefinition = this.services.getRepositoryService().getProcessDefinition(processDefinitionId); String processDefinitionKey = processDefinition.getKey(); return this.cancelAll(processDefinitionId, processDefinitionKey); } /** * @param latestProcessDefinitionId A process definition identifier to NOT clear. All other versions will be cleared. * @return A set of execution identifiers that were in the now cleared map. */ public synchronized Set<String> clearOtherVersions(String latestProcessDefinitionId) throws Exception { public synchronized Set<String> cancelAllOtherVersions(String latestProcessDefinitionId) throws Exception { ProcessDefinition latestProcessDefinition = this.services.getRepositoryService().getProcessDefinition(latestProcessDefinitionId); String processDefinitionKey = latestProcessDefinition.getKey(); Set<String> executionIds = new HashSet<>(); Collection<String> processDefinitionIds = this.processDefinitionKeyMap.get(processDefinitionKey); for (String processDefinitionId : processDefinitionIds) { for (String processDefinitionId : processDefinitionIds) executionIds.addAll(this.cancelAll(processDefinitionId, processDefinitionKey)); return executionIds; } private synchronized boolean cancel(String processDefinitionId, String executionId) throws Exception { this.logger.trace("Cancelling execution: {}: {}", processDefinitionId, executionId); Collection<String> activityIds = this.processDefinitionActivityMap.remove(processDefinitionId); if (activityIds == null) { this.logger.debug("No activities/executions to clear for process definition: {}", processDefinitionId); return false; } for (String activityId : activityIds) { this.logger.trace("Clearing process definition activity: {}: {}", processDefinitionId, activityId); Pair<String, String> key = this.toKey(processDefinitionId, activityId); Collection<String> activityExecutionIds = this.activityExecutionMap.get(key); if (activityExecutionIds.remove(executionId)) return true; } return false; } private synchronized Set<String> cancelAll(String processDefinitionId, String processDefinitionKey) throws Exception { Set<String> executionIds = new HashSet<>(); this.processDefinitionKeyMap.removeMapping(processDefinitionKey, processDefinitionId); Collection<String> activityIds = this.processDefinitionActivityMap.remove(processDefinitionId); Loading @@ -157,7 +213,6 @@ public class MqExecutionService { if (activityExecutionIds != null) executionIds.addAll(activityExecutionIds); } } return executionIds; } Loading