org.ikasan.flow.visitorPattern.VisitingInvokerFlow Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ikasan-flow-visitorPattern Show documentation
Show all versions of ikasan-flow-visitorPattern Show documentation
Ikasan EIP Flow implementation based on the Visitor design pattern
/*
* $Id$
* $URL$
*
* ====================================================================
* Ikasan Enterprise Integration Platform
*
* Distributed under the Modified BSD License.
* Copyright notice: The copyright for this software and a full listing
* of individual contributors are as shown in the packaged copyright.txt
* file.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the ORGANIZATION nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
package org.ikasan.flow.visitorPattern;
import org.apache.log4j.Logger;
import org.ikasan.flow.configuration.FlowPersistentConfiguration;
import org.ikasan.flow.event.FlowEventFactory;
import org.ikasan.spec.component.endpoint.Consumer;
import org.ikasan.spec.configuration.ConfiguredResource;
import org.ikasan.spec.configuration.DynamicConfiguredResource;
import org.ikasan.spec.error.reporting.ErrorReportingService;
import org.ikasan.spec.error.reporting.IsErrorReportingServiceAware;
import org.ikasan.spec.event.EventFactory;
import org.ikasan.spec.event.EventListener;
import org.ikasan.spec.event.Resubmission;
import org.ikasan.spec.exclusion.ExclusionService;
import org.ikasan.spec.flow.*;
import org.ikasan.spec.management.ManagedResource;
import org.ikasan.spec.management.ManagedResourceRecoveryManager;
import org.ikasan.spec.monitor.Monitor;
import org.ikasan.spec.monitor.MonitorSubject;
import org.ikasan.spec.monitor.Notifier;
import org.ikasan.spec.recovery.RecoveryManager;
import org.ikasan.spec.serialiser.SerialiserFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Default implementation of a Flow
*
* @author Ikasan Development Team
*/
@SuppressWarnings(value={"unchecked", "javadoc"})
public class VisitingInvokerFlow implements Flow, EventListener>, MonitorSubject, IsErrorReportingServiceAware, ConfiguredResource
{
/** logger instance */
private static Logger logger = Logger.getLogger(VisitingInvokerFlow.class);
/** thread states */
private static Boolean ACTIVE = true;
private static Boolean INACTIVE = false;
/** running state string constant */
private static String RUNNING = "running";
/** stopped state string constant */
private static String STOPPED = "stopped";
/** recovering state string constant */
private static String RECOVERING = "recovering";
/** stoppedInError state string constant */
private static String STOPPED_IN_ERROR = "stoppedInError";
/** paused state string constant */
private static String PAUSED = "paused";
/** Name of this flow */
private String name;
/** Name of the module within which this flow exists */
private String moduleName;
/** The flow event listener */
private FlowEventListener flowEventListener;
/** flow configuration implementation */
private FlowConfiguration flowConfiguration;
/** flow monitor implementation */
private Monitor monitor;
/** stateful recovery manager implementation */
private RecoveryManager, FlowInvocationContext> recoveryManager;
/** startup failure flag */
private boolean flowInitialisationFailure = false;
/** has the consumer been paused */
private boolean consumerPaused = false;
/** default managed resource recovery manager factory */
private ManagedResourceRecoveryManagerFactory managedResourceRecoveryManagerFactory = new ManagedResourceRecoveryManagerFactory();
/** default event factory */
private EventFactory eventFactory = new FlowEventFactory();
/** Event Exclusion Service */
private ExclusionService exclusionService;
/** flow configuration implementation */
private ExclusionFlowConfiguration exclusionFlowConfiguration;
/** errorReportingService handle */
private ErrorReportingService errorReportingService;
/** serialiserFactory handle */
private SerialiserFactory serialiserFactory;
/** List of listeners for the end of the FlowInvocation using the associated context */
private List flowInvocationContextListeners;
/** flag to control invocation of the context listeners at runtime, defaults to true */
protected volatile boolean invokeContextListeners = true;
/** persistent flow configuration */
private FlowPersistentConfiguration flowPersistentConfiguration = new FlowPersistentConfiguration();
/** configured resource id */
private String configuredResourceId;
/** map to keep track of active threads */
private ConcurrentHashMap activeThreads = new ConcurrentHashMap();
/** we don't want to wait for ever for the flow to stop. Default 30 seconds */
private long stopWaitTimeout = 30000;
/**
* Constructor
* @param name
* @param moduleName
* @param flowConfiguration
* @param recoveryManager
* @param exclusionService
*/
public VisitingInvokerFlow(String name, String moduleName, FlowConfiguration flowConfiguration,
RecoveryManager, FlowInvocationContext> recoveryManager,
ExclusionService exclusionService, SerialiserFactory serialiserFactory)
{
this(name, moduleName, flowConfiguration, null, recoveryManager, exclusionService, serialiserFactory);
}
/**
* Constructor
* @param name
* @param moduleName
* @param flowConfiguration
* @param exclusionFlowConfiguration
* @param recoveryManager
* @param exclusionService
*/
public VisitingInvokerFlow(String name, String moduleName, FlowConfiguration flowConfiguration, ExclusionFlowConfiguration exclusionFlowConfiguration,
RecoveryManager, FlowInvocationContext> recoveryManager,
ExclusionService exclusionService, SerialiserFactory serialiserFactory)
{
this.name = name;
if(name == null)
{
throw new IllegalArgumentException("name cannot be 'null'");
}
this.moduleName = moduleName;
if(moduleName == null)
{
throw new IllegalArgumentException("moduleName cannot be 'null'");
}
this.flowConfiguration = flowConfiguration;
if(flowConfiguration == null)
{
throw new IllegalArgumentException("flowConfiguration cannot be 'null'");
}
this.exclusionFlowConfiguration = exclusionFlowConfiguration;
this.recoveryManager = recoveryManager;
if(recoveryManager == null)
{
throw new IllegalArgumentException("recoveryManager cannot be 'null'");
}
this.exclusionService = exclusionService;
if(exclusionService == null)
{
throw new IllegalArgumentException("exclusionService cannot be 'null'");
}
this.serialiserFactory = serialiserFactory;
if(serialiserFactory == null)
{
throw new IllegalArgumentException("serialiserFactory cannot be 'null'");
}
this.configuredResourceId = this.moduleName + "-" + this.name;
}
/**
* Get the stop wait timeout
* @return
*/
public long getStopWaitTimeout()
{
return stopWaitTimeout;
}
/**
* Set the stop wait timeout
* @param stopWaitTimeout
*/
public void setStopWaitTimeout(long stopWaitTimeout)
{
this.stopWaitTimeout = stopWaitTimeout;
}
/**
* Get this flow name
* return name
*/
public String getName()
{
return this.name;
}
/**
* Get this module name
* String moduleName
*/
public String getModuleName()
{
return this.moduleName;
}
/**
* Allow override of the managed resource recovery manager within this class.
* Mainly for testability.
* @param managedResourceRecoveryManagerFactory
*/
public void setManagedResourceRecoveryManagerFactory (ManagedResourceRecoveryManagerFactory managedResourceRecoveryManagerFactory)
{
this.managedResourceRecoveryManagerFactory = managedResourceRecoveryManagerFactory;
}
/**
* Start this flow
*/
public void start()
{
try
{
this.flowInitialisationFailure = false;
if(isRunning())
{
logger.info("flow [" + name + "] module ["
+ moduleName
+ "] is already running. Ignoring start request.");
return;
}
_start();
startConsumer();
logger.info("Started Flow[" + this.name + "] in Module[" + this.moduleName + "]");
}
finally
{
this.notifyMonitor();
}
}
public void startPause()
{
try
{
_start();
pause();
}
finally
{
this.notifyMonitor();
}
}
protected void _start()
{
try
{
this.flowInitialisationFailure = false;
this.recoveryManager.initialise();
// configure any registered monitors marked as configured
if(this.monitor != null)
{
if(this.monitor instanceof ConfiguredResource)
{
ConfiguredResource configuredMonitor = (ConfiguredResource)monitor;
if( configuredMonitor.getConfiguredResourceId() == null )
{
configuredMonitor.setConfiguredResourceId(this.moduleName + this.name + "_monitor");
}
this.flowConfiguration.configure(configuredMonitor);
}
List monitorNotifiers = this.monitor.getNotifiers();
if(monitorNotifiers == null)
{
logger.warn("Flow monitor has no registered notifiers. Flow state changes will not be notified!");
}
else
{
for(Notifier monitorNotifier : monitorNotifiers)
{
if(monitorNotifier instanceof ConfiguredResource)
{
ConfiguredResource configuredMonitorNotifier = (ConfiguredResource)monitorNotifier;
if( configuredMonitorNotifier.getConfiguredResourceId() == null )
{
configuredMonitorNotifier.setConfiguredResourceId(this.moduleName + this.name + "_monitor_notifier_" + monitorNotifier.getClass().getSimpleName());
}
this.flowConfiguration.configure(configuredMonitorNotifier);
}
}
}
}
// configure exclusion flow resources that are marked as configurable
if(this.exclusionFlowConfiguration != null)
{
configure(this.exclusionFlowConfiguration.getConfiguredResourceFlowElements());
// register the errorReportingService with those components in the exclusion flow requiring it
for(FlowElement flowElement:this.exclusionFlowConfiguration.getErrorReportingServiceAwareFlowElements())
{
IsErrorReportingServiceAware component = flowElement.getFlowComponent();
component.setErrorReportingService(this.errorReportingService);
}
}
// configure business flow resources that are marked as configurable
configure(this.flowConfiguration.getConfiguredResourceFlowElements());
// configure the flow elements
configureFlowElements(this.flowConfiguration.getFlowElements());
// configure the flow itself
this.flowConfiguration.configure(this);
this.invokeContextListeners = this.flowPersistentConfiguration.getInvokeContextListeners();
// register the errorReportingService with those components requiring it
for(FlowElement flowElement:this.flowConfiguration.getErrorReportingServiceAwareFlowElements())
{
IsErrorReportingServiceAware component = flowElement.getFlowComponent();
component.setErrorReportingService(this.errorReportingService);
}
}
catch(RuntimeException e)
{
this.flowInitialisationFailure = true;
throw e;
}
try
{
startManagedResources();
}
catch(RuntimeException e)
{
this.flowInitialisationFailure = true;
this.stopManagedResources();
throw e;
}
}
/**
* Configure the given list of configured flowElements
* @param flowElements
*/
private void configure(List> flowElements)
{
for(FlowElement flowElement:flowElements)
{
// set the default configured resource id if none previously set.
if(flowElement.getFlowComponent().getConfiguredResourceId() == null)
{
flowElement.getFlowComponent().setConfiguredResourceId(this.moduleName + this.name + flowElement.getComponentName());
}
this.flowConfiguration.configure(flowElement.getFlowComponent());
}
}
/**
* Configure the given list of configured flowElements
* @param flowElements
*/
private void configureFlowElements(List> flowElements)
{
for(FlowElement> flowElement:flowElements)
{
// set the default configured resource id if none previously set.
if(flowElement.getConfiguredResourceId() == null)
{
flowElement.setConfiguredResourceId(this.moduleName + this.name + flowElement.getComponentName() + "_element");
}
this.flowConfiguration.configure(flowElement);
}
}
public void pause()
{
try
{
// stop any active recovery
if(this.recoveryManager.isRecovering())
{
this.recoveryManager.cancel();
}
// stop consumer and remove the listener
Consumer,?> consumer = this.flowConfiguration.getConsumerFlowElement().getFlowComponent();
consumer.stop();
this.consumerPaused = true;
logger.info("Paused Flow[" + this.name + "] in Module[" + this.moduleName + "]");
}
finally
{
this.notifyMonitor();
}
}
public void resume()
{
try
{
if(isRunning())
{
logger.info("flow [" + name + "] module ["
+ moduleName
+ "] is already running. Ignoring resume request.");
return;
}
startConsumer();
logger.info("Resumed Flow[" + this.name + "] in Module[" + this.moduleName + "]");
}
finally
{
this.notifyMonitor();
}
}
/**
* Is this flow in a running / recovering state
* @return
*/
public boolean isRunning()
{
String currentState = this.getState();
return currentState.equals(RECOVERING) || currentState.equals(RUNNING);
}
/**
* Is this flow in a paused state
* @return
*/
public boolean isPaused()
{
String currentState = this.getState();
return currentState.equals(PAUSED);
}
@Override
public void startContextListeners()
{
invokeContextListeners = true;
}
@Override
public void stopContextListeners()
{
invokeContextListeners = false;
}
@Override
public boolean areContextListenersRunning()
{
return invokeContextListeners;
}
/**
* Start the consumer component.
*/
protected void startConsumer()
{
this.consumerPaused = false;
FlowElement consumerFlowElement = this.flowConfiguration.getConsumerFlowElement();
// start the consumer
Consumer>,EventFactory> consumer = consumerFlowElement.getFlowComponent();
consumer.setListener(this);
// if event factory has not been set on the consumer then set the default
if(consumer.getEventFactory() == null)
{
consumer.setEventFactory(eventFactory);
}
try
{
consumer.start();
}
catch(RuntimeException e)
{
this.recoveryManager.recover(consumerFlowElement.getComponentName(), e);
}
}
/**
* Stop all managed resources from left to right.
*/
protected void stopManagedResources()
{
stopManagedResourceFlowElements(this.flowConfiguration.getManagedResourceFlowElements());
if(this.exclusionFlowConfiguration != null)
{
stopManagedResourceFlowElements(this.exclusionFlowConfiguration.getManagedResourceFlowElements());
}
}
private void stopManagedResourceFlowElements(List> flowElements) {
for(FlowElement flowElement:flowElements)
{
logger.info("Stopping managed component ["
+ flowElement.getComponentName() + "]...");
flowElement.getFlowComponent().stopManagedResource();
logger.info("Successfully stopped managed component ["
+ flowElement.getComponentName() + "]");
}
}
/**
* Start the components marked as including Managed Resources.
* These component are started from right to left in the flow.
*/
protected void startManagedResources()
{
if(this.exclusionFlowConfiguration != null)
{
List> exclusionFlowElements = this.exclusionFlowConfiguration.getManagedResourceFlowElements();
startManagedResourceFlowElements(exclusionFlowElements);
}
List> flowElements = this.flowConfiguration.getManagedResourceFlowElements();
this.recoveryManager.setManagedResources(flowElements);
startManagedResourceFlowElements(flowElements);
}
private void startManagedResourceFlowElements(List> flowElements)
{
for(int index=flowElements.size()-1; index >= 0; index--)
{
FlowElement flowElement = flowElements.get(index);
try
{
ManagedResource managedResource = flowElement.getFlowComponent();
managedResource.setManagedResourceRecoveryManager( managedResourceRecoveryManagerFactory.getManagedResourceRecoveryManager(flowElement.getComponentName()) );
logger.info("Starting managed component ["
+ flowElement.getComponentName() + "]...");
managedResource.startManagedResource();
logger.info("Successfully started managed component ["
+ flowElement.getComponentName() + "]");
}
catch(RuntimeException e)
{
if(flowElement.getFlowComponent().isCriticalOnStartup())
{
// log issues as these may get resolved by the recovery manager
logger.warn("Failed to start critical component ["
+ flowElement.getComponentName() + "] " + e.getMessage(), e);
throw e;
}
else
{
// just log any issues as these may get resolved by the recovery manager
logger.warn("Failed to start managed component ["
+ flowElement.getComponentName() + "] " + e.getMessage(), e);
}
}
}
}
/**
* Set the current threads state
*
* @param state
*/
private void setThreadState(boolean state)
{
this.activeThreads.put(Thread.currentThread().getId(), state);
}
/**
* Determine if all threads are inactive
*
* @return
* @throws InterruptedException
*/
private boolean allThreadInactive()
{
long currentTimeMillis = System.currentTimeMillis();
logger.info("Checking if threads are inactive.");
while(true)
{
boolean allInactive = true;
for(Long key: this.activeThreads.keySet())
{
boolean active = this.activeThreads.get(key);
logger.debug("Thread [" + key + "] is active [" + active + "]");
if(active)
{
allInactive = false;
}
}
if(allInactive)
{
logger.info("All threads are inactive.");
this.activeThreads = new ConcurrentHashMap();
return true;
}
else if(System.currentTimeMillis() - currentTimeMillis > this.stopWaitTimeout)
{
logger.info("Timed out waiting for threads to complete.");
this.activeThreads = new ConcurrentHashMap();
return true;
}
else
{
try
{
Thread.sleep(500);
logger.debug("Sleeping waiting for threads to complete.");
}
catch (InterruptedException e)
{
logger.error("Could not put thread to sleep when trying to determine if all threads are inactive.", e);
}
}
}
}
/**
* Stop this flow
*/
public void stop()
{
try
{
this.consumerPaused = false;
// stop any active recovery
if(this.recoveryManager.isRecovering())
{
this.recoveryManager.cancel();
}
// stop consumer and remove the listener
Consumer,?> consumer = this.flowConfiguration.getConsumerFlowElement().getFlowComponent();
consumer.stop();
if(this.allThreadInactive())
{
consumer.setListener(null);
stopManagedResources();
}
logger.info("Stopped Flow[" + this.name + "] in Module[" + this.moduleName + "]");
}
finally
{
this.notifyMonitor();
}
}
/**
* Invoke the flow with a flow event
*/
public void invoke(FlowEvent,?> event)
{
this.setThreadState(ACTIVE);
FlowInvocationContext flowInvocationContext = createFlowInvocationContext();
flowInvocationContext.startFlowInvocation();
// keep a handle on the original assigned eventLifeId as this could change within the flow
Object originalEventLifeIdentifier = event.getIdentifier();
try
{
// TODO part of flow configuration should also disable of exclusionService
if(this.exclusionService.isBlackListed(originalEventLifeIdentifier))
{
this.exclusionService.park(event, originalEventLifeIdentifier);
if(this.exclusionFlowConfiguration != null)
{
invoke(moduleName, name, flowInvocationContext, event, this.exclusionFlowConfiguration.getLeadFlowElement());
}
flowInvocationContext = this.exclusionService.getFlowInvocationContext(originalEventLifeIdentifier);
this.exclusionService.removeBlacklisted(originalEventLifeIdentifier);
}
else
{
configureDynamicConfiguredResources();
// record the event so that it can be replayed if necessary.
if(this.getFlowConfiguration().getReplayRecordService() != null && this.flowPersistentConfiguration.getIsRecording())
{
this.getFlowConfiguration().getReplayRecordService().record(event, this.moduleName,
this.name, this.flowPersistentConfiguration.getRecordedEventTimeToLive());
}
invoke(moduleName, name, flowInvocationContext, event, this.flowConfiguration.getConsumerFlowElement());
updateDynamicConfiguredResources();
if(this.recoveryManager.isRecovering())
{
this.recoveryManager.cancel();
}
}
flowInvocationContext.endFlowInvocation();
}
catch(Throwable throwable)
{
flowInvocationContext.endFlowInvocation();
this.recoveryManager.recover(flowInvocationContext, throwable, event, originalEventLifeIdentifier);
}
finally
{
this.notifyFlowInvocationContextListenersEndFlow(flowInvocationContext);
this.notifyMonitor();
this.setThreadState(INACTIVE);
}
}
/* (non-Javadoc)
* @see org.ikasan.spec.event.EventListener#invoke(org.ikasan.spec.event.Resubmission)
*/
@Override
public void invoke(Resubmission> event)
{
FlowInvocationContext flowInvocationContext = createFlowInvocationContext();
flowInvocationContext.startFlowInvocation();
try
{
configureDynamicConfiguredResources();
invoke(moduleName, name, flowInvocationContext, event.getEvent(), this.flowConfiguration.getConsumerFlowElement());
updateDynamicConfiguredResources();
if(this.recoveryManager.isRecovering())
{
this.recoveryManager.cancel();
}
flowInvocationContext.endFlowInvocation();
}
catch(Throwable throwable)
{
flowInvocationContext.endFlowInvocation();
this.recoveryManager.recover(flowInvocationContext, throwable, event.getEvent(), event.getEvent().getIdentifier());
}
finally
{
this.notifyFlowInvocationContextListenersEndFlow(flowInvocationContext);
this.notifyMonitor();
}
}
private void configureDynamicConfiguredResources()
{
for(FlowElement flowElement:this.flowConfiguration.getDynamicConfiguredResourceFlowElements())
{
this.flowConfiguration.configure(flowElement.getFlowComponent());
}
}
private void updateDynamicConfiguredResources()
{
for(FlowElement flowElement:this.flowConfiguration.getDynamicConfiguredResourceFlowElements())
{
this.flowConfiguration.update(flowElement.getFlowComponent());
}
}
protected void invoke(String moduleName, String flowName, FlowInvocationContext flowInvocationContext,
FlowEvent flowEvent, FlowElement flowElement)
{
while (flowElement != null)
{
try
{
notifyFlowInvocationContextListenersSnapEvent(flowElement, flowEvent);
flowElementCaptureMetrics(flowElement);
flowElement = flowElement.getFlowElementInvoker().invoke(flowEventListener, moduleName, flowName, flowInvocationContext, flowEvent, flowElement);
}
catch (ClassCastException e)
{
throw new RuntimeException("Unable to find method signature in module["
+ moduleName + "] flow[" + flowName + "] on component ["
+ flowElement.getComponentName() + "] for payload class ["
+ flowEvent.getPayload().getClass().getName() + "]", e);
}
}
}
/**
* Invoke the recover manager to act on the passed exception.
* @param throwable
*/
public void invoke(Throwable throwable)
{
try
{
this.recoveryManager.recover(this.flowConfiguration.getConsumerFlowElement().getComponentName(), throwable);
}
finally
{
this.notifyMonitor();
}
}
/**
* Notification to all registered MonitorListener
of the current state of the Initiator
*/
protected void notifyMonitor()
{
if(this.monitor != null)
{
try
{
this.monitor.invoke(this.getState());
}
catch(RuntimeException e)
{
// don't let the failure of the monitor interfere with
// the operation of the business flow
logger.error("Failed to notify the registered monitor", e);
}
}
}
protected void flowElementCaptureMetrics(FlowElement flowElement)
{
try
{
if(flowElement.getConfiguration() != null)
{
flowElement.getFlowElementInvoker().setIgnoreContextInvocation(!((FlowElementConfiguration)flowElement.getConfiguration()).getCaptureMetrics());
}
else
{
flowElement.getFlowElementInvoker().setIgnoreContextInvocation(true);
}
}
catch (RuntimeException e)
{
flowElement.getFlowElementInvoker().setIgnoreContextInvocation(true);
logger.warn("Unable to set the ignore context invocation on flow element, defaulting to true and continuing", e);
}
}
/**
* Notify any FlowInvocationContextListeners that the flow has completed
*/
protected void notifyFlowInvocationContextListenersEndFlow(FlowInvocationContext flowInvocationContext)
{
if (flowInvocationContextListeners != null && this.invokeContextListeners)
{
for (FlowInvocationContextListener listener : flowInvocationContextListeners)
{
try
{
listener.endFlow(flowInvocationContext);
}
catch (RuntimeException e)
{
logger.warn("Unable to invoke FlowInvocationContextListener, continuing", e);
}
}
}
}
/**
* Notify any FlowInvocationContextListeners that to snap an event
*/
protected void notifyFlowInvocationContextListenersSnapEvent(FlowElement flowElement, FlowEvent flowEvent)
{
if(((FlowElementConfiguration)flowElement.getConfiguration()).getSnapEvent() &&
((FlowElementConfiguration)flowElement.getConfiguration()).getCaptureMetrics())
{
if (flowInvocationContextListeners != null && this.invokeContextListeners)
{
for (FlowInvocationContextListener listener : flowInvocationContextListeners)
{
try
{
listener.snapEvent(flowElement, flowEvent);
}
catch (RuntimeException e)
{
logger.warn("Unable to invoke FlowInvocationContextListener snap event, continuing", e);
}
}
}
}
}
/**
* Set the flow monitor
* @param monitor
*/
public void setMonitor(Monitor monitor)
{
this.monitor = monitor;
this.notifyMonitor();
}
/**
* Resolve the state of this flow into a string representation
* @return
*/
public String getState()
{
if(this.recoveryManager.isRecovering())
{
return RECOVERING;
}
else if(this.flowConfiguration.getConsumerFlowElement().getFlowComponent().isRunning())
{
return RUNNING;
}
else if(this.flowInitialisationFailure || this.recoveryManager.isUnrecoverable())
{
return STOPPED_IN_ERROR;
}
else if(this.consumerPaused)
{
return PAUSED;
}
return STOPPED;
}
/**
* Factory method for creating a flow invocation context.
* @return FlowInvocationContext
*/
protected FlowInvocationContext createFlowInvocationContext()
{
return new DefaultFlowInvocationContext();
}
/* (non-Javadoc)
* @see org.ikasan.spec.flow.Flow#getFlowElements()
*/
public List> getFlowElements()
{
return this.flowConfiguration.getFlowElements();
}
/**
* Return the flow element matching this name.
* @return flowElement
*/
public FlowElement> getFlowElement(String name)
{
for(FlowElement flowElement:this.flowConfiguration.getFlowElements())
{
if(flowElement.getComponentName().equals(name))
{
return flowElement;
}
}
return null;
}
/**
* Set the flow event listener
* @param flowEventListener
*/
public void setFlowListener(FlowEventListener flowEventListener)
{
this.flowEventListener = flowEventListener;
}
@Override
public void setErrorReportingService(ErrorReportingService errorReportingService)
{
this.errorReportingService = errorReportingService;
}
/**
* Managed Resource Recovery Manager factory used to create MR recovery manager
* instances per named managed resource.
* @author Ikasan Development Team
*
*/
protected class ManagedResourceRecoveryManagerFactory
{
// cache of managed resource recovery managers
private Map managedResourceRecoveryManagers = new HashMap<>();
/**
* Get the named managed resource recovery manager
* @param name
* @return ManagedResourceRecoveryManager
*/
public ManagedResourceRecoveryManager getManagedResourceRecoveryManager(String name)
{
ManagedResourceRecoveryManager managedResourceRecoveryManager = managedResourceRecoveryManagers.get(name);
if(managedResourceRecoveryManager == null)
{
managedResourceRecoveryManager = new ManagedResourceRecoveryManagerImpl(name);
managedResourceRecoveryManagers.put(name, managedResourceRecoveryManager);
}
return managedResourceRecoveryManager;
}
/**
* Managed Resource Recovery Manager implementation
* @author Ikasan Development Team
*
*/
protected class ManagedResourceRecoveryManagerImpl implements ManagedResourceRecoveryManager
{
/** name of this managed resource recovery manager */
private String name;
/**
* Constructor
* @param name
*/
public ManagedResourceRecoveryManagerImpl(String name)
{
this.name = name;
if(name == null)
{
throw new IllegalArgumentException("name cannot be 'null'");
}
}
/*
* (non-Javadoc)
* @see org.ikasan.spec.management.ManagedResourceRecoveryManager#recover(java.lang.Throwable)
*/
public void recover(Throwable throwable)
{
try
{
recoveryManager.recover(name, throwable);
}
finally
{
notifyMonitor();
}
}
/*
* (non-Javadoc)
* @see org.ikasan.spec.management.ManagedResourceRecoveryManager#isRecovering()
*/
public boolean isRecovering()
{
return recoveryManager.isRecovering();
}
/*
* (non-Javadoc)
* @see org.ikasan.spec.management.ManagedResourceRecoveryManager#cancel()
*/
public void cancel()
{
try
{
recoveryManager.cancel();
}
finally
{
notifyMonitor();
}
}
}
}
/* (non-Javadoc)
* @see org.ikasan.spec.flow.Flow#getConsumerFlowElement()
*/
@Override
public FlowConfiguration getFlowConfiguration()
{
return this.flowConfiguration;
}
/* (non-Javadoc)
* @see org.ikasan.spec.flow.Flow#getSerialiserFactory()
*/
@Override
public SerialiserFactory getSerialiserFactory()
{
return this.serialiserFactory;
}
/* (non-Javadoc)
* @see org.ikasan.spec.configuration.Configured#getConfiguration()
*/
@Override
public FlowPersistentConfiguration getConfiguration()
{
return this.flowPersistentConfiguration;
}
/* (non-Javadoc)
* @see org.ikasan.spec.configuration.Configured#setConfiguration(java.lang.Object)
*/
@Override
public void setConfiguration(FlowPersistentConfiguration configuration)
{
this.flowPersistentConfiguration = configuration;
}
/* (non-Javadoc)
* @see org.ikasan.spec.configuration.ConfiguredResource#getConfiguredResourceId()
*/
@Override
public String getConfiguredResourceId()
{
return this.configuredResourceId;
}
/* (non-Javadoc)
* @see org.ikasan.spec.configuration.ConfiguredResource#setConfiguredResourceId(java.lang.String)
*/
@Override
public void setConfiguredResourceId(String id)
{
this.configuredResourceId = id;
}
@Override
public void setFlowInvocationContextListeners(List flowInvocationContextListeners)
{
this.flowInvocationContextListeners = flowInvocationContextListeners;
}
@Override
public List getFlowInvocationContextListeners()
{
return flowInvocationContextListeners;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy