com.amazonaws.services.kinesis.multilang.MultiLangDaemon.java Source code

Java tutorial

Introduction

Here is the source code for com.amazonaws.services.kinesis.multilang.MultiLangDaemon.java

Source

/*
 * Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Amazon Software License (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 * http://aws.amazon.com/asl/
 *
 * or in the "license" file accompanying this file. This file 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.amazonaws.services.kinesis.multilang;

import java.io.IOException;
import java.io.PrintStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.amazonaws.services.kinesis.clientlibrary.lib.worker.KinesisClientLibConfiguration;
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker;

/**
 * Main app that launches the worker that runs the multi-language record processor.
 *
 * Requires a properties file containing configuration for this daemon and the KCL. A properties file should at minimum
 * define these properties:
 *
 * <pre>
 * # The script that abides by the multi-language protocol. This script will
 * # be executed by the MultiLangDaemon, which will communicate with this script
 * # over STDIN and STDOUT according to the multi-language protocol.
 * executableName = sampleapp.py
 *
 * # The name of an Amazon Kinesis stream to process.
 * streamName = words
 *
 * # Used by the KCL as the name of this application. Will be used as the name
 * # of a Amazon DynamoDB table which will store the lease and checkpoint
 * # information for workers with this application name.
 * applicationName = PythonKCLSample
 *
 * # Users can change the credentials provider the KCL will use to retrieve credentials.
 * # The DefaultAWSCredentialsProviderChain checks several other providers, which is
 * # described here:
 * # http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html
 * AWSCredentialsProvider = DefaultAWSCredentialsProviderChain
 * </pre>
 */
public class MultiLangDaemon implements Callable<Integer> {

    private static final Log LOG = LogFactory.getLog(MultiLangDaemon.class);

    private Worker worker;

    /**
     * Constructor.
     * 
     * @param configuration The KCL config to use.
     * @param recordProcessorFactory A record processor factory to create record processors that abide by the multi-lang
     *        protocol.
     * @param workerThreadPool The executor service to run the daemon in.
     */
    public MultiLangDaemon(KinesisClientLibConfiguration configuration,
            MultiLangRecordProcessorFactory recordProcessorFactory, ExecutorService workerThreadPool) {
        this(new Worker(recordProcessorFactory, configuration, workerThreadPool));
    }

    /**
     * 
     * @param worker A worker to use instead of the default worker.
     */
    public MultiLangDaemon(Worker worker) {
        this.worker = worker;
    }

    /**
     * Utility for describing how to run this app.
     * 
     * @param stream Where to output the usage info.
     * @param messageToPrepend An optional error message to describe why the usage is being printed.
     */
    public static void printUsage(PrintStream stream, String messageToPrepend) {
        StringBuilder builder = new StringBuilder();
        if (messageToPrepend != null) {
            builder.append(messageToPrepend);
        }
        builder.append(String.format("java %s <properties file>", MultiLangDaemon.class.getCanonicalName()));
        stream.println(builder.toString());
    }

    @Override
    public Integer call() throws Exception {
        int exitCode = 0;
        try {
            worker.run();
        } catch (Throwable t) {
            LOG.error("Caught throwable while processing data.", t);
            exitCode = 1;
        }
        return exitCode;
    }

    /**
     * @param args Accepts a single argument, that argument is a properties file which provides KCL configuration as
     *        well as the name of an executable.
     */
    public static void main(String[] args) {

        if (args.length == 0) {
            printUsage(System.err, "You must provide a properties file");
            System.exit(1);
        }
        MultiLangDaemonConfig config = null;
        try {
            config = new MultiLangDaemonConfig(args[0]);
        } catch (IOException e) {
            printUsage(System.err, "You must provide a properties file");
            System.exit(1);
        } catch (IllegalArgumentException e) {
            printUsage(System.err, e.getMessage());
            System.exit(1);
        }

        ExecutorService executorService = config.getExecutorService();

        // Daemon
        MultiLangDaemon daemon = new MultiLangDaemon(config.getKinesisClientLibConfiguration(),
                config.getRecordProcessorFactory(), executorService);

        Future<Integer> future = executorService.submit(daemon);
        try {
            System.exit(future.get());
        } catch (InterruptedException | ExecutionException e) {
            LOG.error("Encountered an error while running daemon", e);
        }
        System.exit(1);
    }
}