com.netflix.suro.SuroServer.java Source code

Java tutorial

Introduction

Here is the source code for com.netflix.suro.SuroServer.java

Source

/*
 * Copyright 2013 Netflix, Inc.
 *
 *    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.netflix.suro;

import com.google.common.io.Closeables;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.netflix.governator.configuration.PropertiesConfigurationProvider;
import com.netflix.governator.guice.BootstrapBinder;
import com.netflix.governator.guice.BootstrapModule;
import com.netflix.governator.guice.LifecycleInjector;
import com.netflix.governator.lifecycle.LifecycleManager;
import com.netflix.suro.input.DynamicPropertyInputConfigurator;
import com.netflix.suro.input.SuroInputPlugin;
import com.netflix.suro.routing.DynamicPropertyRoutingMapConfigurator;
import com.netflix.suro.routing.RoutingPlugin;
import com.netflix.suro.server.StatusServer;
import com.netflix.suro.sink.DynamicPropertySinkConfigurator;
import com.netflix.suro.sink.ServerSinkPlugin;
import org.apache.commons.cli.*;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Command line driver for Suro
 * 
 * @author jbae
 * @author elandau
 */
public class SuroServer {
    private static final String PROP_PREFIX = "SuroServer.";
    private static final int DEFAULT_CONTROL_PORT = 9090;
    public static final String OPT_CONTROL_PORT = "controlPort";

    public static void main(String[] args) throws IOException {
        final AtomicReference<Injector> injector = new AtomicReference<Injector>();

        try {
            // Parse the command line
            Options options = createOptions();
            final CommandLine line = new BasicParser().parse(options, args);

            // Load the properties file
            final Properties properties = new Properties();
            if (line.hasOption('p')) {
                properties.load(new FileInputStream(line.getOptionValue('p')));
            }

            // Bind all command line options to the properties with prefix "SuroServer."
            for (Option opt : line.getOptions()) {
                String name = opt.getOpt();
                String value = line.getOptionValue(name);
                String propName = PROP_PREFIX + opt.getArgName();
                if (propName.equals(DynamicPropertyRoutingMapConfigurator.ROUTING_MAP_PROPERTY)) {
                    properties.setProperty(DynamicPropertyRoutingMapConfigurator.ROUTING_MAP_PROPERTY,
                            FileUtils.readFileToString(new File(value)));
                } else if (propName.equals(DynamicPropertySinkConfigurator.SINK_PROPERTY)) {
                    properties.setProperty(DynamicPropertySinkConfigurator.SINK_PROPERTY,
                            FileUtils.readFileToString(new File(value)));
                } else if (propName.equals(DynamicPropertyInputConfigurator.INPUT_CONFIG_PROPERTY)) {
                    properties.setProperty(DynamicPropertyInputConfigurator.INPUT_CONFIG_PROPERTY,
                            FileUtils.readFileToString(new File(value)));
                } else {
                    properties.setProperty(propName, value);
                }
            }

            create(injector, properties);
            injector.get().getInstance(LifecycleManager.class).start();

            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    try {
                        Closeables.close(injector.get().getInstance(LifecycleManager.class), true);
                    } catch (IOException e) {
                        // do nothing because Closeables.close will swallow IOException
                    }
                }
            });

            waitForShutdown(getControlPort(properties));
        } catch (Throwable e) {
            System.err.println("SuroServer startup failed: " + e.getMessage());
            System.exit(-1);
        } finally {
            Closeables.close(injector.get().getInstance(LifecycleManager.class), true);
        }
    }

    public static void create(AtomicReference<Injector> injector, final Properties properties, Module... modules)
            throws Exception {
        // Create the injector
        injector.set(LifecycleInjector.builder().withBootstrapModule(new BootstrapModule() {
            @Override
            public void configure(BootstrapBinder binder) {
                binder.bindConfigurationProvider().toInstance(new PropertiesConfigurationProvider(properties));
            }
        }).withModules(new RoutingPlugin(), new ServerSinkPlugin(), new SuroInputPlugin(),
                new SuroDynamicPropertyModule(), new SuroModule(), StatusServer.createJerseyServletModule())
                .withAdditionalModules(modules).build().createInjector());
    }

    private static void waitForShutdown(int port) throws IOException {
        new SuroControl().start(port);
    }

    private static int getControlPort(Properties properties) {
        String value = properties.getProperty("SuroServer.controlPort");
        if (value == null) {
            return DEFAULT_CONTROL_PORT;
        }
        return Integer.parseInt(value);
    }

    @SuppressWarnings("static-access")
    private static Options createOptions() {
        Option propertyFile = OptionBuilder.withArgName("serverProperty").hasArg()
                .withDescription("server property file path").create('p');

        Option mapFile = OptionBuilder.withArgName("routingMap").hasArg().isRequired(true)
                .withDescription("message routing map file path").create('m');

        Option sinkFile = OptionBuilder.withArgName("sinkConfig").hasArg().isRequired(true).withDescription("sink")
                .create('s');

        Option inputFile = OptionBuilder.withArgName("inputConfig").hasArg().isRequired(true)
                .withDescription("input").create('i');

        Option accessKey = OptionBuilder.withArgName("AWSAccessKey").hasArg().isRequired(false)
                .withDescription("AWSAccessKey").create('a');

        Option secretKey = OptionBuilder.withArgName("AWSSecretKey").hasArg().isRequired(false)
                .withDescription("AWSSecretKey").create('k');

        Option controlPort = OptionBuilder.withArgName(OPT_CONTROL_PORT).hasArg().isRequired(false)
                .withDescription("The port used to send command to this server").create('c');

        Options options = new Options();
        options.addOption(propertyFile);
        options.addOption(mapFile);
        options.addOption(sinkFile);
        options.addOption(inputFile);
        options.addOption(accessKey);
        options.addOption(secretKey);
        options.addOption(controlPort);

        return options;
    }
}