com.ottogroup.bi.spqr.pipeline.component.emitter.EmitterRuntimeEnvironment.java Source code

Java tutorial

Introduction

Here is the source code for com.ottogroup.bi.spqr.pipeline.component.emitter.EmitterRuntimeEnvironment.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.component.emitter;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.codahale.metrics.Counter;
import com.codahale.metrics.Timer;
import com.ottogroup.bi.spqr.exception.RequiredInputMissingException;
import com.ottogroup.bi.spqr.pipeline.message.StreamingDataMessage;
import com.ottogroup.bi.spqr.pipeline.queue.StreamingMessageQueueConsumer;
import com.ottogroup.bi.spqr.pipeline.queue.strategy.StreamingMessageQueueWaitStrategy;

/**
 * Provides a runtime environment for {@link Emitter} instances. The environment retrieves all
 * incoming {@link StreamingDataMessage} instances from the attached {@link StreamingMessageQueueConsumer}
 * and provides them to the assigned {@link Emitter} for further processing.
 * @author mnxfst
 *
 */
public class EmitterRuntimeEnvironment implements Runnable {

    /** our faithful logging facility ... ;-) */
    private static final Logger logger = Logger.getLogger(EmitterRuntimeEnvironment.class);

    /** identifier of processing node the runtime environment belongs to*/
    private final String processingNodeId;
    /** identifier of pipeline the runtime environment belongs to */
    private final String pipelineId;
    /** identifier of emitter assigned to this runtime environment */
    private final String emitterId;
    /** reference to emitter instance being fed with incoming messages */
    private final Emitter emitter;
    /** provides read access to assigned source queue */
    private final StreamingMessageQueueConsumer queueConsumer;
    /** indicates whether the environment is still running */
    private boolean running = false;
    /** message counter metric */
    private Counter messageCounter = null;
    /** insertion timer metric */
    private Timer messageEmitDurationTimer = null;

    /**
     * Initializes the runtime environment using the provided input
     * @param processingNodeId
     * @param pipelineId
     * @param emitter
     * @param queueConsumer
     * @throws RequiredInputMissingException
     */
    public EmitterRuntimeEnvironment(final String processingNodeId, final String pipelineId, final Emitter emitter,
            final StreamingMessageQueueConsumer queueConsumer) throws RequiredInputMissingException {

        ///////////////////////////////////////////////////////////////////
        // validate input
        if (StringUtils.isBlank(processingNodeId))
            throw new RequiredInputMissingException("Missing required processing node identifier");
        if (StringUtils.isBlank(pipelineId))
            throw new RequiredInputMissingException("Missing required pipeline identifier");
        if (emitter == null)
            throw new RequiredInputMissingException("Missing required emitter");
        if (queueConsumer == null)
            throw new RequiredInputMissingException("Missing required input queue consumer");
        //
        ///////////////////////////////////////////////////////////////////

        this.processingNodeId = StringUtils.lowerCase(StringUtils.trim(processingNodeId));
        this.pipelineId = StringUtils.lowerCase(StringUtils.trim(pipelineId));
        this.emitterId = StringUtils.lowerCase(StringUtils.trim(emitter.getId()));
        this.emitter = emitter;
        this.queueConsumer = queueConsumer;

        this.running = true;

        if (logger.isDebugEnabled())
            logger.debug("emitter init [node=" + this.processingNodeId + ", pipeline=" + this.pipelineId
                    + ", emitter=" + this.emitterId + "]");

    }

    /**
     * @see java.lang.Runnable#run()
     */
    public void run() {

        // fetch the wait strategy attached to the queue (provided through the queue consumer)
        StreamingMessageQueueWaitStrategy queueWaitStrategy = this.queueConsumer.getWaitStrategy();
        while (running) {

            try {
                // fetch message from queue consumer via strategy
                StreamingDataMessage message = queueWaitStrategy.waitFor(this.queueConsumer);
                if (message != null && message.getBody() != null) {

                    @SuppressWarnings("resource") // context#close() calls context#stop -> avoid additional call, thus accept warning
                    Timer.Context timerContext = (this.messageEmitDurationTimer != null
                            ? this.messageEmitDurationTimer.time()
                            : null);

                    this.emitter.onMessage(message);

                    if (timerContext != null)
                        timerContext.stop();

                    if (this.messageCounter != null)
                        this.messageCounter.inc();
                }

            } catch (InterruptedException e) {
                // do nothing - waiting was interrupted            
            } catch (Exception e) {
                logger.error("processing error [node=" + this.processingNodeId + ", pipeline=" + this.pipelineId
                        + ", emitter=" + this.emitterId + "]: " + e.getMessage(), e);
                // TODO add handler for responding to errors
            }
        }
    }

    /**
     * Shuts down the runtime environment as well as the attached {@link Emitter}
     */
    public void shutdown() {
        this.running = false;
        try {
            this.emitter.shutdown();
            if (logger.isDebugEnabled())
                logger.debug("emitter shutdown [node=" + this.processingNodeId + ", pipeline=" + this.pipelineId
                        + ", emitter=" + this.emitterId + "]");
        } catch (Exception e) {
            logger.error("emitter shutdown error [node=" + this.processingNodeId + ", pipeline=" + this.pipelineId
                    + ", emitter=" + this.emitterId + "]: " + e.getMessage(), e);
        }

    }

    /**
     * @return the running
     */
    public boolean isRunning() {
        return running;
    }

    /**
     * @param messageCounter the messageCounter to set
     */
    public void setMessageCounter(Counter messageCounter) {
        this.messageCounter = messageCounter;
    }

    /**
     * @param messageEmitDurationTimer the messageEmitDurationTimer to set
     */
    public void setMessageEmitDurationTimer(Timer messageEmitDurationTimer) {
        this.messageEmitDurationTimer = messageEmitDurationTimer;
    }

}