com.ottogroup.bi.spqr.pipeline.MicroPipelineManager.java Source code

Java tutorial

Introduction

Here is the source code for com.ottogroup.bi.spqr.pipeline.MicroPipelineManager.java

Source

/**
 * 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.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
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.spqr.exception.ComponentInitializationFailedException;
import com.ottogroup.bi.spqr.exception.NonUniqueIdentifierException;
import com.ottogroup.bi.spqr.exception.PipelineInstantiationFailedException;
import com.ottogroup.bi.spqr.exception.QueueInitializationFailedException;
import com.ottogroup.bi.spqr.exception.RequiredInputMissingException;
import com.ottogroup.bi.spqr.pipeline.component.MicroPipelineComponent;
import com.ottogroup.bi.spqr.repository.ComponentRepository;

/**
 * Manages the instantiation and monitoring of {@link MicroPipeline micro pipelines} 
 * @author mnxfst
 * @since Mar 13, 2015
 * TODO using one execution service may cause troubles, need to check on that but for the moment having only one suffice
 */
public class MicroPipelineManager {

    private static final Logger logger = Logger.getLogger(MicroPipelineManager.class);

    /** keeps track of all registered pipeline instances */
    private final Map<String, MicroPipeline> pipelines = new HashMap<>();
    /** reference towards execution service which is to be used for runtime environment execution */
    private final ExecutorService executorService;
    /** micro pipeline factory */
    private final MicroPipelineFactory microPipelineFactory;
    /** identifier of processing node this factory lives on */
    private final String processingNodeId;

    /**
     * Initializes the micro pipeline manager
     * @param processingNodeId identifier of node this manager lives on
     * @param componentRepository reference to {@link ComponentRepository} which provides access to all {@link MicroPipelineComponent}
     * @param maxNumberOfThreads max. number of threads assigned to {@link ExecutorService} (1 = single threaded, n = fixed number of threads, other = cached thread pool)
     * @throws RequiredInputMissingException   
     */
    public MicroPipelineManager(final String processingNodeId, final ComponentRepository componentRepository,
            final int maxNumberOfThreads) throws RequiredInputMissingException {

        //////////////////////////////////////////////////////////////////////////////
        // validate provided input
        if (componentRepository == null)
            throw new RequiredInputMissingException("Missing required component repository");
        if (StringUtils.isBlank(processingNodeId))
            throw new RequiredInputMissingException("Missing required processing node identifier");
        //
        //////////////////////////////////////////////////////////////////////////////

        this.processingNodeId = StringUtils.lowerCase(StringUtils.trim(processingNodeId));
        this.microPipelineFactory = new MicroPipelineFactory(this.processingNodeId, componentRepository);

        if (maxNumberOfThreads == 1)
            this.executorService = Executors.newSingleThreadExecutor();
        else if (maxNumberOfThreads > 1)
            this.executorService = Executors.newFixedThreadPool(maxNumberOfThreads);
        else
            this.executorService = Executors.newCachedThreadPool();

    }

    /**
     * Initializes the micro pipeline manager - <b>used for testing purpose only</b>
     * @param processingNodeId identifier of node this manager lives on
     * @param factory
     * @param executorService
     * @throws RequiredInputMissingException   
     */
    protected MicroPipelineManager(final String processingNodeId, final MicroPipelineFactory factory,
            final ExecutorService executorService) throws RequiredInputMissingException {

        //////////////////////////////////////////////////////////////////////////////
        // validate provided input
        if (factory == null)
            throw new RequiredInputMissingException("Missing required component repository");
        if (executorService == null)
            throw new RequiredInputMissingException("Missing required executor service");
        if (StringUtils.isBlank(processingNodeId))
            throw new RequiredInputMissingException("Missing required processing node identifier");
        //
        //////////////////////////////////////////////////////////////////////////////

        this.processingNodeId = StringUtils.lowerCase(StringUtils.trim(processingNodeId));
        this.microPipelineFactory = factory;
        this.executorService = executorService;
    }

    /**
     * Instantiates and executes the {@link MicroPipeline} described by the given {@link MicroPipelineConfiguration}
     * @param configuration
     * @throws RequiredInputMissingException
     * @throws QueueInitializationFailedException
     * @throws ComponentInitializationFailedException
     * @throws PipelineInstantiationFailedException
     */
    public String executePipeline(final MicroPipelineConfiguration configuration)
            throws RequiredInputMissingException, QueueInitializationFailedException,
            ComponentInitializationFailedException, PipelineInstantiationFailedException,
            NonUniqueIdentifierException {

        ///////////////////////////////////////////////////////////
        // validate input
        if (configuration == null)
            throw new RequiredInputMissingException("Missing required pipeline configuration");
        //
        ///////////////////////////////////////////////////////////

        String id = StringUtils.lowerCase(StringUtils.trim(configuration.getId()));
        if (this.pipelines.containsKey(id))
            throw new NonUniqueIdentifierException("A pipeline already exists for id '" + id + "'");

        MicroPipeline pipeline = this.microPipelineFactory.instantiatePipeline(configuration, this.executorService);
        if (pipeline != null)
            this.pipelines.put(id, pipeline);
        else
            throw new PipelineInstantiationFailedException("Failed to instantiate pipeline '"
                    + configuration.getId() + "'. Reason: null returned by pipeline factory");

        if (logger.isDebugEnabled())
            logger.debug("pipeline registered[id=" + configuration.getId() + "]");

        return id;
    }

    /**
     * Shuts down the referenced pipeline
     * @param pipelineId
     */
    public String shutdownPipeline(final String pipelineId) {

        String id = StringUtils.lowerCase(StringUtils.trim(pipelineId));
        MicroPipeline pipeline = this.pipelines.get(id);
        if (pipeline != null) {
            pipeline.shutdown();
            this.pipelines.remove(id);

            if (logger.isDebugEnabled())
                logger.debug("pipeline shutdown[id=" + pipelineId + "]");
        }

        return pipelineId;
    }

    /**
     * Returns true if a {@link MicroPipeline} for the given identifier exists otherwise
     * it returns false
     * @param pipelineId
     * @return
     */
    public boolean hasPipeline(final String pipelineId) {
        return this.pipelines.containsKey(StringUtils.lowerCase(StringUtils.trim(pipelineId)));
    }

    /**
     * Returns the number of registered {@link MicroPipeline} instances
     * @return
     */
    public int getNumOfRegisteredPipelines() {
        return this.pipelines.size();
    }

    /**
     * Returns a list of identifiers belonging to registered {@link MicroPipeline}
     * @return
     */
    public Set<String> getPipelineIds() {
        return (this.pipelines != null && !this.pipelines.isEmpty()) ? this.pipelines.keySet()
                : Collections.<String>emptySet();
    }

    /**
     * Returns the {@link MicroPipelineConfiguration} for all registered {@link MicroPipeline} instances
     * @return
     */
    public Map<String, MicroPipelineConfiguration> getPipelineConfigurations() {
        Map<String, MicroPipelineConfiguration> cfgs = new HashMap<>();
        for (final MicroPipeline pipeline : this.pipelines.values()) {
            cfgs.put(pipeline.getId(), pipeline.getConfiguration());
        }
        return cfgs;
    }

    /**
     * Shuts down the manager by stopping all running {@link MicroPipeline} instances
     */
    public void shutdown() {
        for (final String pipelineId : this.pipelines.keySet()) {
            final MicroPipeline pipeline = this.pipelines.get(pipelineId);
            try {
                pipeline.shutdown();
                logger.info("pipeline shutdown[id=" + pipelineId + "]");
            } catch (Exception e) {
                logger.error("failed to shutdown pipeline [id=" + pipelineId + "]. Reason: " + e.getMessage(), e);
            }
        }
    }

    /**
     * Returns the processing node identifier
     * @return
     */
    public String getProcessingNodeId() {
        return processingNodeId;
    }

}