Java tutorial
/** * Copyright 2015 Otto (GmbH & Co KG) * * 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 com.ottogroup.bi.spqr.pipeline; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.concurrent.ExecutorService; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import com.codahale.metrics.Counter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import com.ottogroup.bi.spqr.exception.ComponentInitializationFailedException; import com.ottogroup.bi.spqr.exception.QueueInitializationFailedException; import com.ottogroup.bi.spqr.exception.RequiredInputMissingException; import com.ottogroup.bi.spqr.metrics.MetricsHandler; import com.ottogroup.bi.spqr.metrics.MetricsReporterFactory; import com.ottogroup.bi.spqr.pipeline.component.MicroPipelineComponent; import com.ottogroup.bi.spqr.pipeline.component.MicroPipelineComponentConfiguration; import com.ottogroup.bi.spqr.pipeline.component.MicroPipelineComponentType; import com.ottogroup.bi.spqr.pipeline.component.emitter.Emitter; import com.ottogroup.bi.spqr.pipeline.component.emitter.EmitterRuntimeEnvironment; import com.ottogroup.bi.spqr.pipeline.component.operator.DelayedResponseOperator; import com.ottogroup.bi.spqr.pipeline.component.operator.DelayedResponseOperatorRuntimeEnvironment; import com.ottogroup.bi.spqr.pipeline.component.operator.DelayedResponseOperatorWaitStrategy; import com.ottogroup.bi.spqr.pipeline.component.operator.DirectResponseOperator; import com.ottogroup.bi.spqr.pipeline.component.operator.DirectResponseOperatorRuntimeEnvironment; import com.ottogroup.bi.spqr.pipeline.component.operator.MessageCountResponseWaitStrategy; import com.ottogroup.bi.spqr.pipeline.component.operator.OperatorTriggeredWaitStrategy; import com.ottogroup.bi.spqr.pipeline.component.operator.TimerBasedResponseWaitStrategy; import com.ottogroup.bi.spqr.pipeline.component.source.Source; import com.ottogroup.bi.spqr.pipeline.component.source.SourceRuntimeEnvironment; import com.ottogroup.bi.spqr.pipeline.exception.UnknownWaitStrategyException; import com.ottogroup.bi.spqr.pipeline.queue.StreamingMessageQueue; import com.ottogroup.bi.spqr.pipeline.queue.StreamingMessageQueueConfiguration; import com.ottogroup.bi.spqr.pipeline.queue.chronicle.DefaultStreamingMessageQueue; import com.ottogroup.bi.spqr.pipeline.queue.memory.InMemoryStreamingMessageQueue; import com.ottogroup.bi.spqr.repository.ComponentRepository; /** * Manages the instantiation of {@link MicroPipeline micro pipelines} * @author mnxfst * @since Mar 6, 2015 */ public class MicroPipelineFactory { /** our faithful logging service ... ;-) */ private static final Logger logger = Logger.getLogger(MicroPipelineFactory.class); /** reference towards component repository */ private final ComponentRepository componentRepository; /** identifier of processing node this factory lives on */ private final String processingNodeId; /** * Initializes the factory using the provided input * @param processingNodeId * @param componentRepository */ public MicroPipelineFactory(final String processingNodeId, final ComponentRepository componentRepository) { this.processingNodeId = processingNodeId; this.componentRepository = componentRepository; } /** * Instantiates the {@link MicroPipeline} according to the provided {@link MicroPipelineComponentConfiguration} * @param cfg * @param executorService * @return * @throws RequiredInputMissingException * TODO validate micro pipeline for path from source to emitter */ public MicroPipeline instantiatePipeline(final MicroPipelineConfiguration cfg, final ExecutorService executorService) throws RequiredInputMissingException, QueueInitializationFailedException, ComponentInitializationFailedException { /////////////////////////////////////////////////////////////////////////////////// // validate input if (cfg == null) throw new RequiredInputMissingException("Missing required configuration"); if (StringUtils.isBlank(cfg.getId())) throw new RequiredInputMissingException("Missing required micro pipeline id"); if (cfg.getComponents() == null || cfg.getComponents().isEmpty()) throw new RequiredInputMissingException("Missing required component configurations"); if (cfg.getQueues() == null || cfg.getQueues().isEmpty()) throw new RequiredInputMissingException("Missing required queue configurations"); // /////////////////////////////////////////////////////////////////////////////////// MetricRegistry.name(StringUtils.lowerCase(StringUtils.trim(this.processingNodeId)), StringUtils.lowerCase(StringUtils.trim(cfg.getId())), "queue", "messages"); final MetricsHandler metricsHandler = new MetricsHandler(); MetricsReporterFactory.attachReporters(metricsHandler, cfg.getMetricsReporter()); /////////////////////////////////////////////////////////////////////////////////// // (1) initialize queues // keep track of all ready created queue instances and create a new one for each configuration // entry. if creation fails for any reason, all previously created queues are shut down and // a queue initialization exception is thrown MicroPipeline microPipeline = new MicroPipeline(StringUtils.lowerCase(StringUtils.trim(cfg.getId())), cfg); for (final StreamingMessageQueueConfiguration queueConfig : cfg.getQueues()) { String id = StringUtils.lowerCase(StringUtils.trim(queueConfig.getId())); // a queue for that identifier already exists: kill the pipeline and tell the caller about it if (microPipeline.hasQueue(id)) { logger.error("queue initialization failed [id=" + id + "]. Forcing shutdown of all queues."); microPipeline.shutdown(); throw new QueueInitializationFailedException("Non-unique queue identifier found [id=" + id + "]"); } // try to instantiate the queue, if it fails .... shutdown queues initialized so far and throw an exception try { StreamingMessageQueue queueInstance = initializeQueue(queueConfig); ///////////////////////////////////////////////////////////////////// // add queue message insertion and retrieval counters if (queueConfig.isAttachInsertionCounter()) { final Counter queueInsertionCounter = metricsHandler.counter( MetricRegistry.name(StringUtils.lowerCase(StringUtils.trim(this.processingNodeId)), StringUtils.lowerCase(StringUtils.trim(cfg.getId())), "queue", id, "messages", "in"), true); queueInstance.setMessageInsertionCounter(queueInsertionCounter); if (logger.isDebugEnabled()) logger.debug("queue[id=" + id + "]: message insertion counter attached"); } if (queueConfig.isAttachRetrievalCounter()) { final Counter queueRetrievalCounter = metricsHandler.counter( MetricRegistry.name(StringUtils.lowerCase(StringUtils.trim(this.processingNodeId)), StringUtils.lowerCase(StringUtils.trim(cfg.getId())), "queue", id, "messages", "out"), true); queueInstance.setMessageRetrievalCounter(queueRetrievalCounter); if (logger.isDebugEnabled()) logger.debug("queue[id=" + id + "]: message retrieval counter attached"); } ///////////////////////////////////////////////////////////////////// microPipeline.addQueue(id, queueInstance); logger.info("queue initialized[id=" + id + "]"); } catch (Exception e) { logger.error("queue initialization failed [id=" + id + "]. Forcing shutdown of all queues."); microPipeline.shutdown(); throw new QueueInitializationFailedException( "Failed to initialize queue [id=" + id + "]. Reason: " + e.getMessage(), e); } } /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // (2) initialize components final Map<String, MicroPipelineComponent> components = new HashMap<>(); boolean sourceComponentFound = false; boolean emitterComponentFound = false; for (final MicroPipelineComponentConfiguration componentCfg : cfg.getComponents()) { String id = StringUtils.lowerCase(StringUtils.trim(componentCfg.getId())); // a component for that identifier already exists: kill the pipeline and tell the caller about it if (microPipeline.hasComponent(id)) { logger.error("component initialization failed [id=" + id + ", class=" + componentCfg.getName() + ", version=" + componentCfg.getVersion() + "]. Forcing shutdown of all queues and components."); microPipeline.shutdown(); throw new ComponentInitializationFailedException( "Non-unique component identifier found [id=" + id + "]"); } // try to instantiate component, if it fails .... shutdown queues and components initialized so far and throw an exception try { MicroPipelineComponent component = initializeComponent(componentCfg, microPipeline.getQueues()); if (component.getType() == null) { logger.error("component initialization failed [id=" + id + ", class=" + componentCfg.getName() + ", version=" + componentCfg.getVersion() + "]. Type missing. Forcing shutdown of all queues and components."); microPipeline.shutdown(); throw new ComponentInitializationFailedException( "Failed to initialize component [id=" + id + ", class=" + componentCfg.getName() + ", version=" + componentCfg.getVersion() + "]. Reason: type missing"); } final StreamingMessageQueue fromQueue = microPipeline .getQueue(StringUtils.lowerCase(StringUtils.trim(componentCfg.getFromQueue()))); final StreamingMessageQueue toQueue = microPipeline .getQueue(StringUtils.lowerCase(StringUtils.trim(componentCfg.getToQueue()))); Counter messageCounter = null; if (componentCfg.isAttachMessageCounter()) { messageCounter = metricsHandler.counter( MetricRegistry.name(StringUtils.lowerCase(StringUtils.trim(this.processingNodeId)), StringUtils.lowerCase(StringUtils.trim(cfg.getId())), "component", id, "messages", "count"), true); } switch (component.getType()) { case SOURCE: { SourceRuntimeEnvironment srcEnv = new SourceRuntimeEnvironment(this.processingNodeId, cfg.getId(), (Source) component, toQueue.getProducer()); /////////////////////////////////////////////// // attach monitoring components if (messageCounter != null) srcEnv.setMessageCounter(messageCounter); /////////////////////////////////////////////// microPipeline.addSource(id, srcEnv); sourceComponentFound = true; break; } case DIRECT_RESPONSE_OPERATOR: { DirectResponseOperatorRuntimeEnvironment directResponseEnv = new DirectResponseOperatorRuntimeEnvironment( this.processingNodeId, cfg.getId(), (DirectResponseOperator) component, fromQueue.getConsumer(), toQueue.getProducer()); /////////////////////////////////////////////// // attach monitoring components if (componentCfg.isAttachProcessingTimer()) { final Timer messageProcessingTimer = metricsHandler.timer( MetricRegistry.name(StringUtils.lowerCase(StringUtils.trim(this.processingNodeId)), StringUtils.lowerCase(StringUtils.trim(cfg.getId())), "component", id, "messages", "timer")); directResponseEnv.setMessageProcessingTimer(messageProcessingTimer); } if (messageCounter != null) directResponseEnv.setMessageCounter(messageCounter); /////////////////////////////////////////////// microPipeline.addOperator(id, directResponseEnv); break; } case DELAYED_RESPONSE_OPERATOR: { DelayedResponseOperatorRuntimeEnvironment delayedResponseEnv = new DelayedResponseOperatorRuntimeEnvironment( this.processingNodeId, cfg.getId(), (DelayedResponseOperator) component, getResponseWaitStrategy(componentCfg), fromQueue.getConsumer(), toQueue.getProducer(), executorService); /////////////////////////////////////////////// // attach monitoring components if (messageCounter != null) delayedResponseEnv.setMessageCounter(messageCounter); /////////////////////////////////////////////// microPipeline.addOperator(id, delayedResponseEnv); break; } case EMITTER: { EmitterRuntimeEnvironment emitterEnv = new EmitterRuntimeEnvironment(this.processingNodeId, cfg.getId(), (Emitter) component, fromQueue.getConsumer()); /////////////////////////////////////////////// // attach monitoring components if (componentCfg.isAttachProcessingTimer()) { final Timer messageEmitDurationTimer = metricsHandler.timer( MetricRegistry.name(StringUtils.lowerCase(StringUtils.trim(this.processingNodeId)), StringUtils.lowerCase(StringUtils.trim(cfg.getId())), "component", id, "messages", "emit", "duration")); emitterEnv.setMessageEmitDurationTimer(messageEmitDurationTimer); } if (messageCounter != null) emitterEnv.setMessageCounter(messageCounter); /////////////////////////////////////////////// microPipeline.addEmitter(id, emitterEnv); emitterComponentFound = true; break; } } components.put(id, component); } catch (Exception e) { logger.error("component initialization failed [id=" + id + ", class=" + componentCfg.getName() + ", version=" + componentCfg.getVersion() + "]. Forcing shutdown of all queues and components. Reason: " + e.getMessage(), e); microPipeline.shutdown(); throw new ComponentInitializationFailedException( "Failed to initialize component [id=" + id + ", class=" + componentCfg.getName() + ", version=" + componentCfg.getVersion() + "]. Reason: " + e.getMessage(), e); } } if (!sourceComponentFound) { microPipeline.shutdown(); throw new RequiredInputMissingException("Missing required source component"); } if (!emitterComponentFound) { microPipeline.shutdown(); throw new RequiredInputMissingException("Missing required emitter component"); } /////////////////////////////////////////////////////////////////////////////////// microPipeline.attachComponentMetricsHandler(metricsHandler); /////////////////////////////////////////////////////////////////////////////////// // (3) start components --> ramp up their runtime environments for (String sourceId : microPipeline.getSources().keySet()) { executorService.submit(microPipeline.getSources().get(sourceId)); if (logger.isDebugEnabled()) logger.debug("Started runtime environment for source [id=" + sourceId + "]"); } for (String directResponseOperatorId : microPipeline.getDirectResponseOperators().keySet()) { executorService.submit(microPipeline.getDirectResponseOperators().get(directResponseOperatorId)); if (logger.isDebugEnabled()) logger.debug("Started runtime environment for direct response operator [id=" + directResponseOperatorId + "]"); } for (String delayedResponseOperatorId : microPipeline.getDelayedResponseOperators().keySet()) { executorService.submit(microPipeline.getDelayedResponseOperators().get(delayedResponseOperatorId)); if (logger.isDebugEnabled()) logger.debug("Started runtime environment for delayed response operator [id=" + delayedResponseOperatorId + "]"); } for (String emitterId : microPipeline.getEmitters().keySet()) { executorService.submit(microPipeline.getEmitters().get(emitterId)); if (logger.isDebugEnabled()) logger.debug("Started runtime environment for emitter [id=" + emitterId + "]"); } if (logger.isDebugEnabled()) logger.debug("Started stats collector"); // /////////////////////////////////////////////////////////////////////////////////// return microPipeline; } /** * Initializes a {@link StreamingMessageQueue} instance according to provided information. * @param queueConfiguration+ * @return * @throws RequiredInputMissingException * @throws QueueInitializationFailedException */ protected StreamingMessageQueue initializeQueue(final StreamingMessageQueueConfiguration queueConfiguration) throws RequiredInputMissingException, QueueInitializationFailedException { /////////////////////////////////////////////////////////////////////////////////// // validate input if (queueConfiguration == null) throw new RequiredInputMissingException("Missing required queue configuration"); if (StringUtils.isBlank(queueConfiguration.getId())) throw new RequiredInputMissingException("Missing required queue identifier"); // /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // check properties for optional settings boolean inMemoryQueue = false; if (queueConfiguration.getProperties() != null && !queueConfiguration.getProperties().isEmpty()) { String queueType = StringUtils.lowerCase(StringUtils .trim(queueConfiguration.getProperties().getProperty(StreamingMessageQueue.CFG_QUEUE_TYPE))); inMemoryQueue = StringUtils.equalsIgnoreCase(queueType, InMemoryStreamingMessageQueue.CFG_QUEUE_TYPE); } /////////////////////////////////////////////////////////////////////////////////// if (inMemoryQueue) { try { StreamingMessageQueue queue = new InMemoryStreamingMessageQueue(); queue.setId(StringUtils.lowerCase(StringUtils.trim(queueConfiguration.getId()))); queue.initialize((queueConfiguration.getProperties() != null ? queueConfiguration.getProperties() : new Properties())); return queue; } catch (Exception e) { throw new QueueInitializationFailedException("Failed to initialize streaming message queue '" + queueConfiguration.getId() + "'. Error: " + e.getMessage()); } } try { StreamingMessageQueue queue = new DefaultStreamingMessageQueue(); queue.setId(StringUtils.lowerCase(StringUtils.trim(queueConfiguration.getId()))); queue.initialize((queueConfiguration.getProperties() != null ? queueConfiguration.getProperties() : new Properties())); return queue; } catch (Exception e) { throw new QueueInitializationFailedException("Failed to initialize streaming message queue '" + queueConfiguration.getId() + "'. Error: " + e.getMessage()); } } /** * Initializes a {@link MicroPipelineComponent} instance according to provided information * @param componentConfiguration * @return * @throws RequiredInputMissingException * @throws ComponentInitializationFailedException * TODO test for settings that must be provided for type SOURCE * TODO test for settings that must be provided for type EMITTER * TODO test for settings that must be provided for type OPERATOR * TODO test queue references in toQueues and fromQueues * TODO test component instantiation */ protected MicroPipelineComponent initializeComponent( final MicroPipelineComponentConfiguration componentConfiguration, final Map<String, StreamingMessageQueue> queues) throws RequiredInputMissingException, ComponentInitializationFailedException { /////////////////////////////////////////////////////////////////////////////////// // validate input if (componentConfiguration == null) throw new RequiredInputMissingException("Missing required component configuration"); if (StringUtils.isBlank(componentConfiguration.getId())) throw new RequiredInputMissingException("Missing required component identifier"); if (componentConfiguration.getType() == null) throw new RequiredInputMissingException("Missing required component type"); if (StringUtils.isBlank(componentConfiguration.getName())) throw new RequiredInputMissingException("Missing required component name"); if (StringUtils.isBlank(componentConfiguration.getVersion())) throw new RequiredInputMissingException("Missing required component version"); if (componentConfiguration.getSettings() == null) throw new RequiredInputMissingException("Missing required component settings"); // //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// // validate settings for components of type: SOURCE if (componentConfiguration.getType() == MicroPipelineComponentType.SOURCE) { if (StringUtils.isBlank(componentConfiguration.getToQueue())) throw new RequiredInputMissingException("Missing required queues to write content to"); if (!queues.containsKey(StringUtils.lowerCase(StringUtils.trim(componentConfiguration.getToQueue())))) throw new RequiredInputMissingException( "Unknown destination queue '" + componentConfiguration.getToQueue() + "'"); //////////////////////////////////////////////////////////////////////////////////// // validate settings for components of type: DIRECT_RESPONSE_OPERATOR } else if (componentConfiguration.getType() == MicroPipelineComponentType.DIRECT_RESPONSE_OPERATOR) { if (StringUtils.isBlank(componentConfiguration.getToQueue())) throw new RequiredInputMissingException("Missing required queues to write content to"); if (!queues.containsKey(StringUtils.lowerCase(StringUtils.trim(componentConfiguration.getToQueue())))) throw new RequiredInputMissingException( "Unknown destination queue '" + componentConfiguration.getToQueue() + "'"); if (StringUtils.isBlank(componentConfiguration.getFromQueue())) throw new RequiredInputMissingException("Missing required queues to retrieve content from"); if (!queues.containsKey(StringUtils.lowerCase(StringUtils.trim(componentConfiguration.getFromQueue())))) throw new RequiredInputMissingException( "Unknown source queue '" + componentConfiguration.getFromQueue() + "'"); //////////////////////////////////////////////////////////////////////////////////// // validate settings for components of type: DELAYED_RESPONSE_OPERATOR } else if (componentConfiguration.getType() == MicroPipelineComponentType.DELAYED_RESPONSE_OPERATOR) { if (StringUtils.isBlank(componentConfiguration.getToQueue())) throw new RequiredInputMissingException("Missing required queues to write content to"); if (!queues.containsKey(StringUtils.lowerCase(StringUtils.trim(componentConfiguration.getToQueue())))) throw new RequiredInputMissingException( "Unknown destination queue '" + componentConfiguration.getToQueue() + "'"); if (StringUtils.isBlank(componentConfiguration.getFromQueue())) throw new RequiredInputMissingException("Missing required queues to retrieve content from"); if (!queues.containsKey(StringUtils.lowerCase(StringUtils.trim(componentConfiguration.getFromQueue())))) throw new RequiredInputMissingException( "Unknown source queue '" + componentConfiguration.getFromQueue() + "'"); if (StringUtils.isBlank(componentConfiguration.getSettings() .getProperty(DelayedResponseOperator.CFG_WAIT_STRATEGY_NAME))) throw new RequiredInputMissingException( "Missing required settings for wait strategy applied to delayed response operator"); //////////////////////////////////////////////////////////////////////////////////// // validate settings for components of type: EMITTER } else if (componentConfiguration.getType() == MicroPipelineComponentType.EMITTER) { if (StringUtils.isBlank(componentConfiguration.getFromQueue())) throw new RequiredInputMissingException("Missing required queues to retrieve content from"); if (!queues.containsKey(StringUtils.lowerCase(StringUtils.trim(componentConfiguration.getFromQueue())))) throw new RequiredInputMissingException( "Unknown source queue '" + componentConfiguration.getFromQueue() + "'"); } // //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// // instantiate component class try { return this.componentRepository.newInstance(componentConfiguration.getId(), componentConfiguration.getName(), componentConfiguration.getVersion(), componentConfiguration.getSettings()); } catch (Exception e) { throw new ComponentInitializationFailedException("Failed to initialize component '" + componentConfiguration.getId() + "'. Error: " + e.getMessage(), e); } // //////////////////////////////////////////////////////////////////////////////////// } /** * Instantiates, initializes and returns the {@link DelayedResponseOperatorWaitStrategy} configured for the {@link DelayedResponseOperator} * whose {@link MicroPipelineComponentConfiguration configuration} is provided when calling this method. * @param delayedResponseOperatorCfg * @return */ protected DelayedResponseOperatorWaitStrategy getResponseWaitStrategy( final MicroPipelineComponentConfiguration delayedResponseOperatorCfg) throws RequiredInputMissingException, UnknownWaitStrategyException { ///////////////////////////////////////////////////////////////////////////////////// // validate input if (delayedResponseOperatorCfg == null) throw new RequiredInputMissingException("Missing required delayed response operator configuration"); if (delayedResponseOperatorCfg.getSettings() == null) throw new RequiredInputMissingException("Missing required delayed response operator settings"); String strategyName = StringUtils.lowerCase(StringUtils.trim(delayedResponseOperatorCfg.getSettings() .getProperty(DelayedResponseOperator.CFG_WAIT_STRATEGY_NAME))); if (StringUtils.isBlank(strategyName)) throw new RequiredInputMissingException( "Missing required strategy name expected as part of operator settings ('" + DelayedResponseOperator.CFG_WAIT_STRATEGY_NAME + "')"); // ///////////////////////////////////////////////////////////////////////////////////// if (logger.isDebugEnabled()) logger.debug("Settings provided for strategy '" + strategyName + "'"); Properties strategyProperties = new Properties(); for (Enumeration<Object> keyEnumerator = delayedResponseOperatorCfg.getSettings().keys(); keyEnumerator .hasMoreElements();) { String key = (String) keyEnumerator.nextElement(); if (StringUtils.startsWith(key, DelayedResponseOperator.CFG_WAIT_STRATEGY_SETTINGS_PREFIX)) { String waitStrategyCfgKey = StringUtils.substring(key, StringUtils.lastIndexOf(key, ".") + 1); if (StringUtils.isNoneBlank(waitStrategyCfgKey)) { String waitStrategyCfgValue = delayedResponseOperatorCfg.getSettings().getProperty(key); strategyProperties.put(waitStrategyCfgKey, waitStrategyCfgValue); if (logger.isDebugEnabled()) logger.debug("\t" + waitStrategyCfgKey + ": " + waitStrategyCfgValue); } } } if (StringUtils.equalsIgnoreCase(strategyName, MessageCountResponseWaitStrategy.WAIT_STRATEGY_NAME)) { MessageCountResponseWaitStrategy strategy = new MessageCountResponseWaitStrategy(); strategy.initialize(strategyProperties); return strategy; } else if (StringUtils.equalsIgnoreCase(strategyName, TimerBasedResponseWaitStrategy.WAIT_STRATEGY_NAME)) { TimerBasedResponseWaitStrategy strategy = new TimerBasedResponseWaitStrategy(); strategy.initialize(strategyProperties); return strategy; } else if (StringUtils.equalsIgnoreCase(strategyName, OperatorTriggeredWaitStrategy.WAIT_STRATEGY_NAME)) { OperatorTriggeredWaitStrategy strategy = new OperatorTriggeredWaitStrategy(); strategy.initialize(strategyProperties); return strategy; } throw new UnknownWaitStrategyException("Unknown wait strategy '" + strategyName + "'"); } }