Java tutorial
// // 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; } }