Java tutorial
/** * Copyright 2014 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.asap.pipeline; import java.util.Properties; import java.util.concurrent.ExecutorService; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import com.ottogroup.bi.asap.component.ComponentConfiguration; import com.ottogroup.bi.asap.component.ComponentType; import com.ottogroup.bi.asap.component.emitter.Emitter; import com.ottogroup.bi.asap.component.emitter.executor.EmitterExecutor; import com.ottogroup.bi.asap.component.operator.DelayedResponseOperator; import com.ottogroup.bi.asap.component.operator.DirectResponseOperator; import com.ottogroup.bi.asap.component.operator.executor.DelayedResponseOperatorExecutor; import com.ottogroup.bi.asap.component.operator.executor.DirectResponseOperatorExecutor; import com.ottogroup.bi.asap.component.source.Source; import com.ottogroup.bi.asap.component.source.executor.SourceExecutor; import com.ottogroup.bi.asap.component.strategy.DelayedResponseWaitStrategy; import com.ottogroup.bi.asap.component.strategy.MessageWaitStrategy; import com.ottogroup.bi.asap.component.strategy.YieldMessageWaitStrategy; import com.ottogroup.bi.asap.component.strategy.config.DelayedResponseWaitStrategyConfiguration; import com.ottogroup.bi.asap.component.strategy.config.MessageWaitStrategyConfiguration; import com.ottogroup.bi.asap.exception.ComponentAlreadySubmittedException; import com.ottogroup.bi.asap.exception.ComponentInstantiationFailedException; import com.ottogroup.bi.asap.exception.IllegalComponentSubscriptionException; import com.ottogroup.bi.asap.exception.RequiredInputMissingException; import com.ottogroup.bi.asap.exception.UnknownComponentException; import com.ottogroup.bi.asap.mailbox.DefaultMailbox; import com.ottogroup.bi.asap.mailbox.Mailbox; import com.ottogroup.bi.asap.mailbox.config.MailboxConfiguration; import com.ottogroup.bi.asap.repository.ComponentRepository; /** * Implements a factory for creating {@link MicroPipeline} instances from a given {@link MicroPipelineConfiguration} * @author mnxfst * @since Dec 16, 2014 * TODO more strategies and more flexible * TODO activate exception handling */ public class MicroPipelineFactory { /** our faithful logging service ;-) */ private static final Logger logger = Logger.getLogger(MicroPipelineFactory.class); /** reference to component repository */ private final ComponentRepository componentRepository; /** * Initializes the factory instance using the provided input * @param componentRepository */ public MicroPipelineFactory(final ComponentRepository componentRepository) { this.componentRepository = componentRepository; } /** * Instantiates a {@link MicroPipeline} according to provided {@link MicroPipelineConfiguration} * @param configuration * @param executorService * @return * @throws RequiredInputMissingException * @throws ComponentAlreadySubmittedException * @throws ComponentInstantiationFailedException * @throws UnknownComponentException * @throws IllegalComponentSubscriptionException */ public MicroPipeline instantiate(final MicroPipelineConfiguration configuration, final ExecutorService executorService) throws RequiredInputMissingException, ComponentAlreadySubmittedException, ComponentInstantiationFailedException, UnknownComponentException, IllegalComponentSubscriptionException { ///////////////////////////////////////////////////////////// // validate if (configuration == null) throw new RequiredInputMissingException("Missing required configuration"); if (StringUtils.isBlank(configuration.getId())) throw new RequiredInputMissingException("Missing required micro pipeline identifier"); if (configuration.getComponents() == null || configuration.getComponents().isEmpty()) throw new RequiredInputMissingException("Missing required components"); // ///////////////////////////////////////////////////////////// MicroPipeline mp = new MicroPipeline(configuration.getId(), configuration.getDescription(), executorService); ///////////////////////////////////////////////////////////// // instantiate components for (final ComponentConfiguration cc : configuration.getComponents()) { if (cc != null) { try { switch (cc.getType()) { case DELAYED_RESPONSE_OPERATOR: { mp.submitOperatorExecutor(instantiateDelayedResponseOperatorExecutor(cc)); break; } case DIRECT_RESPONSE_OPERATOR: { mp.submitOperatorExecutor(instantiateDirectResponseOperatorExecutor(cc)); break; } case EMITTER: { mp.submitEmitterExecutor(instantiateEmitterExecutor(cc)); break; } case SOURCE: { mp.submitSourceExecutor(instantiateSourceExecutor(cc)); break; } default: { throw new IllegalStateException("Invalid component type: '" + cc.getType() + "'"); } } } catch (Throwable e) { logger.error("Failed to instantiate micro pipeline [id=" + configuration.getId() + ", componentId=" + cc.getId() + "]. Error: " + e.getMessage()); mp.shutdown(); } } } // ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// // subscribe components to publishers for (final ComponentConfiguration cc : configuration.getComponents()) { if (cc != null && cc.getType() != ComponentType.SOURCE) { try { if (cc.getSubscriptions() == null || cc.getSubscriptions().isEmpty()) throw new RequiredInputMissingException( "Missing required subscriptions for component '" + cc.getId() + "'"); for (String publisherId : cc.getSubscriptions()) { if (StringUtils.isBlank(publisherId)) throw new RequiredInputMissingException( "Empty value found in subscriptions list for component '" + cc.getId() + "'"); mp.subscribe(cc.getId(), publisherId); } } catch (Throwable e) { logger.error("Failed to subscribe micro pipeline components [id=" + configuration.getId() + "]. Error: " + e.getMessage()); mp.shutdown(); } } } // ///////////////////////////////////////////////////////////// return mp; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // EXECUTOR INSTANTIATION /** * Instantiates the {@link SourceExecutor} according to provided configuration * @param cfg expected not to be null * @return * @throws RequiredInputMissingException * @throws UnknownComponentException * @throws ComponentInstantiationFailedException */ protected SourceExecutor instantiateSourceExecutor(final ComponentConfiguration cfg) throws RequiredInputMissingException, ComponentInstantiationFailedException, UnknownComponentException { Mailbox mailbox = getMailbox(cfg.getMailbox()); MessageWaitStrategy messageWaitStrategy = getMessageWaitStrategy(cfg.getMessageWaitStrategy(), mailbox); if (logger.isDebugEnabled()) logger.debug("source message wait strategy[id=" + messageWaitStrategy.getId() + ", type=" + messageWaitStrategy.getClass().getName() + "]"); // TODO get exception handler // TODO get operator exception handler return new SourceExecutor((Source) this.componentRepository.newInstance(cfg.getId(), cfg.getName(), cfg.getVersion(), cfg.getSettings()), messageWaitStrategy, null, null, mailbox); } /** * Instantiates the {@link DelayedResponseOperatorExecutor} according to provided configuration * @param cfg expected not to be null * @return * @throws RequiredInputMissingException * @throws ComponentInstantiationFailedException * @throws UnknownComponentException */ protected DelayedResponseOperatorExecutor instantiateDelayedResponseOperatorExecutor( final ComponentConfiguration cfg) throws RequiredInputMissingException, ComponentInstantiationFailedException, UnknownComponentException { Mailbox mailbox = getMailbox(cfg.getMailbox()); MessageWaitStrategy messageWaitStrategy = getMessageWaitStrategy(cfg.getMessageWaitStrategy(), mailbox); if (logger.isDebugEnabled()) logger.debug("delayed response operator message wait strategy[id=" + messageWaitStrategy.getId() + ", type=" + messageWaitStrategy.getClass().getName() + "]"); // TODO get exception handler // TODO get operator exception handler return new DelayedResponseOperatorExecutor( (DelayedResponseOperator) this.componentRepository.newInstance(cfg.getId(), cfg.getName(), cfg.getVersion(), cfg.getSettings()), getDelayedResponseWaitStrategy(cfg.getDelayedResponseWaitStrategy()), messageWaitStrategy, null, null, mailbox); } /** * Instantiates the {@link DirectResponseOperatorExecutor} according to provided configuration * @param cfg expected not to be null * @return * @throws RequiredInputMissingException * @throws ComponentInstantiationFailedException * @throws UnknownComponentException */ protected DirectResponseOperatorExecutor instantiateDirectResponseOperatorExecutor( final ComponentConfiguration cfg) throws RequiredInputMissingException, ComponentInstantiationFailedException, UnknownComponentException { Mailbox mailbox = getMailbox(cfg.getMailbox()); MessageWaitStrategy messageWaitStrategy = getMessageWaitStrategy(cfg.getMessageWaitStrategy(), mailbox); if (logger.isDebugEnabled()) logger.debug("direct response operator message wait strategy[id=" + messageWaitStrategy.getId() + ", type=" + messageWaitStrategy.getClass().getName() + "]"); // TODO get exception handler // TODO get operator exception handler return new DirectResponseOperatorExecutor((DirectResponseOperator) this.componentRepository .newInstance(cfg.getId(), cfg.getName(), cfg.getVersion(), cfg.getSettings()), messageWaitStrategy, null, null, mailbox); } /** * Instantiates the {@link EmitterExecutor} according to provided configuration * @param cfg * @return * @throws RequiredInputMissingException * @throws ComponentInstantiationFailedException * @throws UnknownComponentException */ protected EmitterExecutor instantiateEmitterExecutor(final ComponentConfiguration cfg) throws RequiredInputMissingException, ComponentInstantiationFailedException, UnknownComponentException { Mailbox mailbox = getMailbox(cfg.getMailbox()); MessageWaitStrategy messageWaitStrategy = getMessageWaitStrategy(cfg.getMessageWaitStrategy(), mailbox); if (logger.isDebugEnabled()) logger.debug("emitter message wait strategy[id=" + messageWaitStrategy.getId() + ", type=" + messageWaitStrategy.getClass().getName() + "]"); // TODO get exception handler // TODO get operator exception handler return new EmitterExecutor((Emitter) this.componentRepository.newInstance(cfg.getId(), cfg.getName(), cfg.getVersion(), cfg.getSettings()), messageWaitStrategy, null, null, mailbox); } // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // STRATEGIES /** * Returns the {@link MessageWaitStrategy} according to the provided configuration * @param configuration * @return * @throws RequiredInputMissingException * @throws UnknownComponentException * @throws ComponentInstantiationFailedException */ protected MessageWaitStrategy getMessageWaitStrategy(final MessageWaitStrategyConfiguration configuration, final Mailbox mailbox) throws RequiredInputMissingException, ComponentInstantiationFailedException, UnknownComponentException { ///////////////////////////////////////////////////////////// // validate mailbox if (mailbox == null) throw new RequiredInputMissingException("Missing required mailbox reference"); // ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// // if no configuration is provided, use default setting - which is by far the worst solution ;-) if (configuration == null) { YieldMessageWaitStrategy strategy = new YieldMessageWaitStrategy(); strategy.setId("waitStrategy-#" + System.currentTimeMillis()); strategy.setMailbox(mailbox); return strategy; } // ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// // validate input if (StringUtils.isBlank(configuration.getId())) throw new RequiredInputMissingException("Missing required strategy id"); if (StringUtils.isBlank(configuration.getName())) throw new RequiredInputMissingException("Missing required strategy name"); if (StringUtils.isBlank(configuration.getVersion())) throw new RequiredInputMissingException("Missing required strategy version"); // ///////////////////////////////////////////////////////////// try { return (MessageWaitStrategy) componentRepository.newInstance(configuration.getId(), configuration.getName(), configuration.getVersion(), configuration.getSettings()); } catch (ClassCastException e) { throw new ComponentInstantiationFailedException( "Failed to convert retrieved instance to mailbox representation. Error: " + e.getMessage()); } } /** * Returns the {@link DelayedResponseWaitStrategy} according to the provided configuration * @param configuration * @return * @throws RequiredInputMissingException * @throws ComponentInstantiationFailedException * @throws UnknownComponentException */ protected DelayedResponseWaitStrategy getDelayedResponseWaitStrategy( final DelayedResponseWaitStrategyConfiguration configuration) throws RequiredInputMissingException, ComponentInstantiationFailedException, UnknownComponentException { ///////////////////////////////////////////////////////////// // validate input if (configuration == null) throw new RequiredInputMissingException("Missing required configuration"); if (StringUtils.isBlank(configuration.getId())) throw new RequiredInputMissingException("Missing required strategy id"); if (StringUtils.isBlank(configuration.getName())) throw new RequiredInputMissingException("Missing required strategy name"); if (StringUtils.isBlank(configuration.getVersion())) throw new RequiredInputMissingException("Missing required strategy version"); // ///////////////////////////////////////////////////////////// try { return (DelayedResponseWaitStrategy) componentRepository.newInstance(configuration.getId(), configuration.getName(), configuration.getVersion(), configuration.getSettings()); } catch (ClassCastException e) { throw new ComponentInstantiationFailedException( "Failed to convert retrieved instance to mailbox representation. Error: " + e.getMessage()); } } // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns the {@link Mailbox} implementation according to the provided configuration * @param configuration * @return * @throws RequiredInputMissingException * @throws UnknownComponentException * @throws ComponentInstantiationFailedException */ protected Mailbox getMailbox(final MailboxConfiguration configuration) throws RequiredInputMissingException, ComponentInstantiationFailedException, UnknownComponentException { ///////////////////////////////////////////////////////////// // return default mailbox if no configuration is provided if (configuration == null) { return getDefaultMailbox(); } // ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// // validate input if (StringUtils.isBlank(configuration.getId())) throw new RequiredInputMissingException("Missing required mailbox id"); if (StringUtils.isBlank(configuration.getName())) throw new RequiredInputMissingException("Missing required mailbox name"); if (StringUtils.isBlank(configuration.getVersion())) throw new RequiredInputMissingException("Missing required mailbox version"); // ///////////////////////////////////////////////////////////// try { return (Mailbox) componentRepository.newInstance(configuration.getId(), configuration.getName(), configuration.getVersion(), configuration.getSettings()); } catch (ClassCastException e) { throw new ComponentInstantiationFailedException( "Failed to convert retrieved instance to mailbox representation. Error: " + e.getMessage()); } } /** * Returns the default mailbox * @return * @throws RequiredInputMissingException */ protected Mailbox getDefaultMailbox() throws RequiredInputMissingException { Properties properties = new Properties(); properties.put(DefaultMailbox.CFG_MAILBOX_SIZE, String.valueOf(1000)); Mailbox mailbox = new DefaultMailbox(); mailbox.init(properties); return mailbox; } }