de.fhg.iais.cortex.Starter.java Source code

Java tutorial

Introduction

Here is the source code for de.fhg.iais.cortex.Starter.java

Source

package de.fhg.iais.cortex;

/******************************************************************************
 * Copyright 2011 (c) Fraunhofer IAIS Netmedia  http://www.iais.fraunhofer.de *
 * ************************************************************************** *
 * 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.                                             *
 ******************************************************************************/

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.logging.Handler;
import java.util.logging.LogManager;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.bridge.SLF4JBridgeHandler;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;

import com.google.common.base.Charsets;

import de.fhg.iais.commons.dbc.DbcException;
import de.fhg.iais.cortex.guice.modules.CortexModuleCollector;
import de.fhg.iais.cortex.guice.modules.CortexPropertiesModule;

/**
 * Starts Cortex. The selective started is called implicitly from the Starter.
 */
public class Starter {
    private static final Logger LOG = LoggerFactory.getLogger(Starter.class);

    private String config = null;
    private final boolean restore = false;

    private final Set<String> autoStartNames = new HashSet<String>();
    private PriorityBasedServerStarter serverStarter;

    /**
     * Starts Cortex.
     * 
     * @param args
     *        the command line arguments
     * @see #configure(ListIterator) The list of applicable command line
     *      arguments
     */
    public static void main(String[] args) {
        try {
            configureLogging();
            Starter starter = new Starter(".");
            starter.start(args);
            LOG.info("Cortex services started.");

            // register a shutdown hook which makes it possible to stop the
            // services with a soft kill
            Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(starter));
        } catch (RuntimeException e) {
            LOG.warn("Start of Cortex failed: " + e.getMessage());
        }
    }

    private static class ShutdownHookThread extends Thread {
        private final Starter starter;

        public ShutdownHookThread(Starter starter) {
            super();
            this.starter = starter;
        }

        @Override
        public void run() {
            try {
                LOG.info("catched shutdown message, stopping services...");
                this.starter.stop();
            } catch (final Exception e) {
                LOG.error("shutdown failed", e);
            }
        }
    }

    private static void configureLogging() {
        String hostAddress = "n/a";
        try {
            hostAddress = InetAddress.getLocalHost().getCanonicalHostName();
        } catch (UnknownHostException e) {
            LOG.warn("Hostname/IP not available");
        }
        MDC.put("host_name", hostAddress);

        // SLF4J is bound to logback
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

        try {
            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(lc);
            lc.reset();
            configurator.doConfigure("conf/logback.xml");
        } catch (JoranException je) {
            je.printStackTrace(); // NOSONAR
        }
        StatusPrinter.printInCaseOfErrorsOrWarnings(lc);

        LOG.info("-- CORTEX starting");

        java.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger("");
        Handler[] handlers = rootLogger.getHandlers();
        for (Handler handler : handlers) {
            rootLogger.removeHandler(handler);
        }
        SLF4JBridgeHandler.install();
    }

    public Starter(String baseDir) {
        LineIterator it = createLineIterator(baseDir + "/conf/startServers.txt");
        try {
            while (it.hasNext()) {
                String nextLine = it.nextLine();
                if (!StringUtils.isEmpty(nextLine) && !isComment(nextLine)) {
                    this.autoStartNames.add(nextLine);
                }
            }
        } finally {
            LineIterator.closeQuietly(it);
        }
    }

    private LineIterator createLineIterator(String filePath) {
        File f = new File(filePath);
        try {
            return FileUtils.lineIterator(f, Charsets.UTF_8.name());
        } catch (IOException e) {
            throw new DbcException(
                    "Error while starting Cortex Server. Reading \"" + f.getAbsolutePath() + "\" failed", e);
        }
    }

    private boolean isComment(String nextLine) {
        return nextLine.startsWith(";") || nextLine.startsWith("#");
    }

    /**
     * Configures this object and starts all configured servers
     * 
     * @param args
     *        the command line arguments used to configure this object
     * @return {@code true} if all configured servers could be started, {@code false} otherwise
     * @see #configure(ListIterator) The list of applicable command line
     *      arguments
     */
    public boolean start(String[] args) {
        this.serverStarter = new PriorityBasedServerStarter(this.autoStartNames);
        configure(args);

        return start();
    }

    /**
     * Configures this object according to a list of command line arguments.
     * 
     * @param args
     * @see #configure(ListIterator) The list of applicable command line
     *      arguments
     */
    private void configure(String[] args) {
        List<String> argList = Arrays.asList(args);
        configure(argList.listIterator());
    }

    /**
     * Configures this object according to a list of command line arguments.<br>
     * <br>
     * The following arguments are recognized and processed from the left to the
     * right. Initially all servers are enabled.<br>
     * <br>
     * -conf &lt;ConfigName&gt; sets the name of the spring main configuration.
     * If there is more than one "-conf" argument, the rightmost one will be
     * used. If there is no "-conf" argument, the "default" spring main
     * configuration is used.<br>
     * <br>
     * +ALL enables all servers.<br>
     * -ALL disables all servers.<br>
     * +&lt;servername&gt; enables a single server.<br>
     * -&lt;servername&gt; disables a single server.<br>
     * <br>
     * Examples: to start all servers without the triplestore:<br>
     * +ALL -TRIPLESTORE<br>
     * Examples: to start only the triplestore server:<br>
     * -ALL +TRIPLESTORE<br>
     * Examples: to start the triplestore and the search server:<br>
     * -ALL +TRIPLESTORE +SEARCH<br>
     * Nonsense-examples: to start the search server:<br>
     * +ALL +TRIPLESTORE -ALL +SEARCH<br>
     */
    private void configure(ListIterator<String> argIterator) {
        while (argIterator.hasNext()) {
            handleNextArgument(argIterator);
        }
    }

    /**
     * Starts the configured servers
     * 
     * @return {@code true} if all servers could be started, {@code false} otherwise
     */
    private boolean start() {
        try {
            CortexPropertiesModule properties;
            try {
                properties = new CortexPropertiesModule(this.config);
                properties.addProperty("restore", String.valueOf(this.restore));
            } catch (IOException e) {
                String path = CortexPropertiesModule.createPath(this.config);
                throw new DbcException("Can't load \"" + path + "\"", e);
            }

            CortexModuleCollector collector = new CortexModuleCollector(properties);
            this.serverStarter.start(collector);
            return true;
        } catch (InterruptedException e) {
            LOG.warn("An exception aborted the starter.");
            throw new DbcException("Server start has been interrupted by an exception.", e);
        }
    }

    private void handleNextArgument(ListIterator<String> argIterator) {
        String arg = argIterator.next();
        if (StringUtils.isEmpty(arg)) {
            return;
        }

        if (arg.equals("-conf")) {
            if (!argIterator.hasNext()) {
                LOG.warn("Found option \"-conf\" without [name of configuration] as next argument - ignored");
            } else {
                this.config = argIterator.next();
            }
        } else if (!handleServerArgument(arg)) {
            LOG.warn("Found unknown argument \"{}\" - ignored", arg);
        }
    }

    private boolean handleServerArgument(String arg) {
        switch (arg.charAt(0)) {
        case '+':
            return setServerEnabled(arg.substring(1), true);
        case '-':
            return setServerEnabled(arg.substring(1), false);
        default:
            return false;
        }
    }

    private boolean setServerEnabled(String argument, boolean serverEnabled) {
        if (argument.equalsIgnoreCase("all")) {
            for (String serverName : this.autoStartNames) {
                this.serverStarter.setServerEnabled(serverName, serverEnabled);
            }
        } else {
            this.serverStarter.setServerEnabled(argument, serverEnabled);
        }

        return true;
    }

    /**
     * Stops the cortex.
     */
    public boolean stop() {
        try {
            this.serverStarter.stop();
            return true;
        } catch (InterruptedException e) {
            LOG.warn("Stopping Cortex Server has been interrupted by an exception.");
            throw new DbcException(e);
        }
    }
}