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.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; 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.PipelineAlreadyRegisteredException; import com.ottogroup.bi.asap.exception.PipelineReplacementFailedException; import com.ottogroup.bi.asap.exception.RequiredInputMissingException; import com.ottogroup.bi.asap.exception.UnknownComponentException; import com.ottogroup.bi.asap.repository.ComponentRepository; /** * Manages all {@link MicroPipeline} instances executed on this node. It receives instantiation and shutdown requests, * ensures that {@link Components component instances} are returned according to requested types and versions and * collects statistical information for all managed pipelines. * @author mnxfst * @since Nov 26, 2014 * TODO assemble and return state information */ public class MicroPipelineManager { /** our faithful logging facility ;-) */ private final static Logger logger = Logger.getLogger(MicroPipelineManager.class); /** references all streaming pipelines by their identifier */ private final Map<String, MicroPipeline> microPipelines = new HashMap<>(); /** thread-pool for operating pipelines - if configuration requires to create one .. micro pipelines may keep track of their own */ private final ExecutorService pipelineThreadPool; /** micro pipeline factory */ private final MicroPipelineFactory factory; /** * Initializes the manager using the provided input * @param componentRepository */ public MicroPipelineManager(final ComponentRepository componentRepository) { this.factory = new MicroPipelineFactory(componentRepository); this.pipelineThreadPool = Executors.newCachedThreadPool(); } /** * Initializes the manager using the provided input * @param componentRepository * @param pipelineThreadPool */ public MicroPipelineManager(final ComponentRepository componentRepository, final ExecutorService pipelineThreadPool) { this.factory = new MicroPipelineFactory(componentRepository); if (pipelineThreadPool != null) this.pipelineThreadPool = pipelineThreadPool; else this.pipelineThreadPool = Executors.newCachedThreadPool(); } /** * Initializes the manager using the provided input * @param microPipelineFactory */ public MicroPipelineManager(final MicroPipelineFactory microPipelineFactory) { this.factory = microPipelineFactory; this.pipelineThreadPool = Executors.newCachedThreadPool(); } /** * Initializes the manager using the provided input * @param microPipelineFactory * @param pipelineThreadPool * */ public MicroPipelineManager(final MicroPipelineFactory microPipelineFactory, final ExecutorService pipelineThreadPool) { this.factory = microPipelineFactory; if (pipelineThreadPool != null) this.pipelineThreadPool = pipelineThreadPool; else this.pipelineThreadPool = Executors.newCachedThreadPool(); } /** * Creates and registers a {@link Pipeline} for the given {@link PipelineConfiguration} * @param pipelineConfiguration * @throws PipelineAlreadyRegisteredException * @throws RequiredInputMissingException * @throws ComponentInstantiationFailedException * @throws UnknownComponentException * @throws IllegalComponentSubscriptionException * @throws ComponentAlreadySubmittedException */ public String instantiatePipeline(final MicroPipelineConfiguration pipelineConfiguration) throws PipelineAlreadyRegisteredException, RequiredInputMissingException, UnknownComponentException, ComponentInstantiationFailedException, ComponentAlreadySubmittedException, IllegalComponentSubscriptionException { ////////////////////////////////////////////////////////////// // validate input if (pipelineConfiguration == null) throw new RequiredInputMissingException("Missing required pipeline configuration"); if (StringUtils.isBlank(pipelineConfiguration.getId())) throw new RequiredInputMissingException("Missing required pipeline identifier"); String pipelineId = StringUtils.lowerCase(StringUtils.trim(pipelineConfiguration.getId())); if (this.microPipelines.containsKey(pipelineId)) throw new PipelineAlreadyRegisteredException("A pipeline already exists for that identifer"); // ////////////////////////////////////////////////////////////// MicroPipeline pipeline = factory.instantiate(pipelineConfiguration, pipelineThreadPool); this.microPipelines.put(pipelineId, pipeline); if (logger.isDebugEnabled()) logger.debug("Pipeline '" + pipelineId + "' successfully instantiated and submitted to thread pool"); return pipelineConfiguration.getId(); } /** * Creates and registers a {@link Pipeline} for the given {@link PipelineConfiguration}. In case a pipeline exists for * the given identifier, it will be forced to shut down and restarted with a new configuration * @param pipelineConfiguration * @param forceReplacement * @throws PipelineAlreadyRegisteredException * @throws RequiredInputMissingException * @throws ComponentInstantiationFailedException * @throws UnknownComponentException * @throws IllegalComponentSubscriptionException * @throws ComponentAlreadySubmittedException */ public String instantiatePipeline(final MicroPipelineConfiguration pipelineConfiguration, final boolean forceReplacement) throws RequiredInputMissingException, UnknownComponentException, ComponentInstantiationFailedException, PipelineReplacementFailedException, ComponentAlreadySubmittedException, IllegalComponentSubscriptionException { // force shutdown if (forceReplacement) { shutdownPipeline(pipelineConfiguration.getId()); } // deploy the pipeline try { instantiatePipeline(pipelineConfiguration); } catch (PipelineAlreadyRegisteredException e) { throw new PipelineReplacementFailedException("Failed to stop and restart pipeline '" + pipelineConfiguration.getId() + "'. Error: " + e.getMessage()); } return pipelineConfiguration.getId(); } /** * Shuts down the referenced pipeline * @param pipelineId * @throws RequiredInputMissingException */ public String shutdownPipeline(final String pipelineId) throws RequiredInputMissingException { ////////////////////////////////////////////////////////////// // validate input if (StringUtils.isBlank(pipelineId)) throw new RequiredInputMissingException("Missing required pipeline identifier"); // ////////////////////////////////////////////////////////////// String pid = StringUtils.lowerCase(StringUtils.trim(pipelineId)); if (this.microPipelines.containsKey(pid)) { MicroPipeline pipeline = this.microPipelines.remove(pid); if (pipeline != null) { pipeline.shutdown(); if (logger.isDebugEnabled()) logger.debug("Pipeline '" + pipelineId + "' successfully shut down"); } } return pid; } /** * Returns the referenced pipeline - used for testing purpose only ... at the moment ;-) * @param pipelineId * @return */ protected MicroPipeline getPipeline(final String pipelineId) { return this.microPipelines.get(StringUtils.lowerCase(StringUtils.trim(pipelineId))); } }