org.apache.cloudstack.ServerDaemon.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cloudstack.ServerDaemon.java

Source

//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 org.apache.cloudstack;

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.URL;
import java.util.Properties;

import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.ForwardedRequestCustomizer;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NCSARequestLog;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.MovedContextHandler;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
import org.eclipse.jetty.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cloud.utils.PropertiesUtil;
import com.google.common.base.Strings;

/***
 * The ServerDaemon class implements the embedded server, it can be started either
 * using JSVC or directly from the JAR along with additional jars not shaded in the uber-jar.
 * Configuration parameters are read from server.properties file available on the classpath.
 */
public class ServerDaemon implements Daemon {
    private static final Logger LOG = LoggerFactory.getLogger(ServerDaemon.class);
    private static final String WEB_XML = "META-INF/webapp/WEB-INF/web.xml";

    /////////////////////////////////////////////////////
    /////////////// Server Properties ///////////////////
    /////////////////////////////////////////////////////

    private static final String BIND_INTERFACE = "bind.interface";
    private static final String CONTEXT_PATH = "context.path";
    private static final String SESSION_TIMEOUT = "session.timeout";
    private static final String HTTP_PORT = "http.port";
    private static final String HTTPS_ENABLE = "https.enable";
    private static final String HTTPS_PORT = "https.port";
    private static final String KEYSTORE_FILE = "https.keystore";
    private static final String KEYSTORE_PASSWORD = "https.keystore.password";
    private static final String WEBAPP_DIR = "webapp.dir";
    private static final String ACCESS_LOG = "access.log";

    ////////////////////////////////////////////////////////
    /////////////// Server Configuration ///////////////////
    ////////////////////////////////////////////////////////

    private Server server;

    private int httpPort = 8080;
    private int httpsPort = 8443;
    private int sessionTimeout = 30;
    private boolean httpsEnable = false;
    private String accessLogFile = "access.log";
    private String bindInterface = "";
    private String contextPath = "/client";
    private String keystoreFile;
    private String keystorePassword;
    private String webAppLocation;

    //////////////////////////////////////////////////
    /////////////// Public methods ///////////////////
    //////////////////////////////////////////////////

    public static void main(final String... anArgs) throws Exception {
        final ServerDaemon daemon = new ServerDaemon();
        daemon.init(null);
        daemon.start();
    }

    @Override
    public void init(final DaemonContext context) {
        final File confFile = PropertiesUtil.findConfigFile("server.properties");
        if (confFile == null) {
            LOG.warn(String.format(
                    "Server configuration file not found. Initializing server daemon on %s:%s, with https.enabled=%s, https.port=%s, context.path=%s",
                    bindInterface, httpPort, httpsEnable, httpsPort, contextPath));
            return;
        }

        LOG.info("Server configuration file found: " + confFile.getAbsolutePath());

        try {
            final Properties properties = PropertiesUtil.loadFromFile(confFile);
            if (properties == null) {
                return;
            }
            setBindInterface(properties.getProperty(BIND_INTERFACE, ""));
            setContextPath(properties.getProperty(CONTEXT_PATH, "/client"));
            setHttpPort(Integer.valueOf(properties.getProperty(HTTP_PORT, "8080")));
            setHttpsEnable(Boolean.valueOf(properties.getProperty(HTTPS_ENABLE, "false")));
            setHttpsPort(Integer.valueOf(properties.getProperty(HTTPS_PORT, "8443")));
            setKeystoreFile(properties.getProperty(KEYSTORE_FILE));
            setKeystorePassword(properties.getProperty(KEYSTORE_PASSWORD));
            setWebAppLocation(properties.getProperty(WEBAPP_DIR));
            setAccessLogFile(properties.getProperty(ACCESS_LOG, "access.log"));
            setSessionTimeout(Integer.valueOf(properties.getProperty(SESSION_TIMEOUT, "30")));
        } catch (final IOException e) {
            LOG.warn("Failed to load configuration from server.properties file", e);
        }
        LOG.info(String.format(
                "Initializing server daemon on %s:%s, with https.enabled=%s, https.port=%s, context.path=%s",
                bindInterface, httpPort, httpsEnable, httpsPort, contextPath));
    }

    @Override
    public void start() throws Exception {
        // Thread pool
        final QueuedThreadPool threadPool = new QueuedThreadPool();
        threadPool.setMinThreads(10);
        threadPool.setMaxThreads(500);

        // Jetty Server
        server = new Server(threadPool);

        // Setup Scheduler
        server.addBean(new ScheduledExecutorScheduler());

        // Setup JMX
        final MBeanContainer mbeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
        server.addBean(mbeanContainer);

        // HTTP config
        final HttpConfiguration httpConfig = new HttpConfiguration();
        httpConfig.addCustomizer(new ForwardedRequestCustomizer());
        httpConfig.setSecureScheme("https");
        httpConfig.setSecurePort(httpsPort);
        httpConfig.setOutputBufferSize(32768);
        httpConfig.setRequestHeaderSize(8192);
        httpConfig.setResponseHeaderSize(8192);
        httpConfig.setSendServerVersion(false);
        httpConfig.setSendDateHeader(false);

        // HTTP Connector
        final ServerConnector httpConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
        httpConnector.setPort(httpPort);
        httpConnector.setHost(bindInterface);
        httpConnector.setIdleTimeout(30000);
        server.addConnector(httpConnector);

        // Setup handlers
        server.setHandler(createHandlers());

        // Extra config options
        server.setStopAtShutdown(true);

        // Configure SSL
        if (httpsEnable && !Strings.isNullOrEmpty(keystoreFile) && new File(keystoreFile).exists()) {
            // SSL Context
            final SslContextFactory sslContextFactory = new SslContextFactory();
            // Define keystore path and passwords
            sslContextFactory.setKeyStorePath(keystoreFile);
            sslContextFactory.setKeyStorePassword(keystorePassword);
            sslContextFactory.setKeyManagerPassword(keystorePassword);

            // HTTPS config
            final HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
            httpsConfig.addCustomizer(new SecureRequestCustomizer());

            // HTTPS connector
            final ServerConnector sslConnector = new ServerConnector(server,
                    new SslConnectionFactory(sslContextFactory, "http/1.1"),
                    new HttpConnectionFactory(httpsConfig));
            sslConnector.setPort(httpsPort);
            sslConnector.setHost(bindInterface);
            server.addConnector(sslConnector);
        }

        server.start();
        server.join();
    }

    @Override
    public void stop() throws Exception {
        server.stop();
    }

    @Override
    public void destroy() {
        server.destroy();
    }

    ///////////////////////////////////////////////////
    /////////////// Private methods ///////////////////
    ///////////////////////////////////////////////////

    private HandlerCollection createHandlers() {
        final WebAppContext webApp = new WebAppContext();
        webApp.setContextPath(contextPath);
        webApp.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
        webApp.getSessionHandler().setMaxInactiveInterval(sessionTimeout * 60);

        // GZIP handler
        final GzipHandler gzipHandler = new GzipHandler();
        gzipHandler.addIncludedMimeTypes("text/html", "text/xml", "text/css", "text/plain", "text/javascript",
                "application/javascript", "application/json", "application/xml");
        gzipHandler.setIncludedMethods("GET", "POST");
        gzipHandler.setCompressionLevel(9);
        gzipHandler.setHandler(webApp);

        if (Strings.isNullOrEmpty(webAppLocation)) {
            webApp.setWar(getShadedWarUrl());
        } else {
            webApp.setWar(webAppLocation);
        }

        // Request log handler
        final RequestLogHandler log = new RequestLogHandler();
        log.setRequestLog(createRequestLog());

        // Redirect root context handler
        MovedContextHandler rootRedirect = new MovedContextHandler();
        rootRedirect.setContextPath("/");
        rootRedirect.setNewContextURL(contextPath);
        rootRedirect.setPermanent(true);

        // Put rootRedirect at the end!
        return new HandlerCollection(log, gzipHandler, rootRedirect);
    }

    private RequestLog createRequestLog() {
        final NCSARequestLog log = new NCSARequestLog();
        final File logPath = new File(accessLogFile);
        final File parentFile = logPath.getParentFile();
        if (parentFile != null) {
            parentFile.mkdirs();
        }
        log.setFilename(logPath.getPath());
        log.setAppend(true);
        log.setLogTimeZone("GMT");
        log.setLogLatency(true);
        return log;
    }

    private URL getResource(String aResource) {
        return Thread.currentThread().getContextClassLoader().getResource(aResource);
    }

    private String getShadedWarUrl() {
        final String urlStr = getResource(WEB_XML).toString();
        return urlStr.substring(0, urlStr.length() - 15);
    }

    ///////////////////////////////////////////
    /////////////// Setters ///////////////////
    ///////////////////////////////////////////

    public void setBindInterface(String bindInterface) {
        this.bindInterface = bindInterface;
    }

    public void setHttpPort(int httpPort) {
        this.httpPort = httpPort;
    }

    public void setHttpsPort(int httpsPort) {
        this.httpsPort = httpsPort;
    }

    public void setContextPath(String contextPath) {
        this.contextPath = contextPath;
    }

    public void setHttpsEnable(boolean httpsEnable) {
        this.httpsEnable = httpsEnable;
    }

    public void setKeystoreFile(String keystoreFile) {
        this.keystoreFile = keystoreFile;
    }

    public void setKeystorePassword(String keystorePassword) {
        this.keystorePassword = keystorePassword;
    }

    public void setAccessLogFile(String accessLogFile) {
        this.accessLogFile = accessLogFile;
    }

    public void setWebAppLocation(String webAppLocation) {
        this.webAppLocation = webAppLocation;
    }

    public void setSessionTimeout(int sessionTimeout) {
        this.sessionTimeout = sessionTimeout;
    }
}