/* * Carrot2 project. * * Copyright (C) 2002-2016, Dawid Weiss, Stanisław Osiński. * All rights reserved. * * Refer to the full license file "carrot2.LICENSE" * in the root folder of the repository checkout or at: * http://www.carrot2.org/carrot2.LICENSE */ package org.carrot2.dcs; import java.net.URL; import java.util.Locale; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.component.LifeCycle.Listener; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.webapp.WebAppContext; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; import org.kohsuke.args4j.ParserProperties; import org.slf4j.Logger; /** * Bootstraps the Document Clustering Server using an embedded Jetty server. */ public class DcsApp { /** * DCS logger. Tests attach to this logger's LOG4J appender. */ final Logger log = org.slf4j.LoggerFactory.getLogger("dcs"); @Option(name = "-port", usage = "Port number to bind to.") int port = 8080; @Option(name = "-v", aliases = { "--verbose" }, required = false, usage = "Print detailed messages.") boolean verbose; @Option(name = "--accept-queue", required = false, usage = "Socket accept queue length.") int acceptQueue; @Option(name = "--threads", required = false, usage = "Maximum number of processing threads.") int processingThreads = Math.max(1, Runtime.getRuntime().availableProcessors() - 1); String appName; Server server; /** * Empty implementation of {@link Listener}. */ private static class ListenerAdapter implements LifeCycle.Listener { public void lifeCycleFailure(LifeCycle lc, Throwable t) { } public void lifeCycleStarted(LifeCycle lc) { } public void lifeCycleStarting(LifeCycle lc) { } public void lifeCycleStopped(LifeCycle lc) { } public void lifeCycleStopping(LifeCycle lc) { } } DcsApp(String appName) { this.appName = appName; } void start() throws Exception { start(null); } void start(String webPathPrefix) throws Exception { configureLogging(); log.info("Starting DCS..."); // Figure out the size of the thread pool and the number of acceptors. [CARROT-1118] final int acceptors = Math.min(16, Runtime.getRuntime().availableProcessors()); final int threads = acceptors * 2 + processingThreads; // The default accept queue is twice the number of processing threads. if (acceptQueue == 0) { acceptQueue = processingThreads * 2; } server = new Server(); final SelectChannelConnector connector = new SelectChannelConnector(); connector.setPort(port); connector.setReuseAddress(false); connector.setAcceptQueueSize(acceptQueue); connector.setAcceptors(acceptors); QueuedThreadPool qtp = new QueuedThreadPool(); qtp.setMaxThreads(threads); connector.setThreadPool(qtp); connector.setSoLingerTime(0); server.addConnector(connector); WebAppContext wac = new WebAppContext(); wac.setContextPath("/"); server.addLifeCycleListener(new ListenerAdapter() { public void lifeCycleStarted(LifeCycle lc) { log.debug( String.format(Locale.ROOT, "Threads: %d, accept queue: %d, tpq size: %d", processingThreads, acceptQueue, threads)); log.info( String.format(Locale.ROOT, "DCS started on port: %d [local: %d]", port, connector.getLocalPort())); } public void lifeCycleFailure(LifeCycle lc, Throwable t) { if (verbose) { log.error("DCS startup failure.", t); } else { log.error("DCS startup failure."); } stop(); } public void lifeCycleStopped(LifeCycle lc) { log.info("DCS stopped."); } }); wac.setParentLoaderPriority(true); final String dcsWar = System.getProperty("dcs.war"); if (dcsWar != null) { // WAR distribution provides, use it wac.setWar(dcsWar); } else { // Run from the provided web dir wac.setWar(webPathPrefix != null ? webPathPrefix + "/web" : "web"); wac.setClassLoader(Thread.currentThread().getContextClassLoader()); /* * Allow context classloader resource loading. */ System.setProperty(RestProcessorServlet.ENABLE_CLASSPATH_LOCATOR, "true"); } if (System.getProperty("dcs.development.mode") != null) { wac.setDefaultsDescriptor("etc/distribution/webdefault.xml"); } server.setHandler(wac); server.setStopAtShutdown(true); // Start the http server. try { server.start(); } catch (Exception e) { stop(); throw e; } } private void configureLogging() { ClassLoader cl = Thread.currentThread().getContextClassLoader(); try { String log4jConfiguration = "log4j-dcs" + (verbose ? "-verbose" : "") + ".xml"; final URL configurationResourceUrl = cl.getResource(log4jConfiguration); if (configurationResourceUrl == null) { System.err.println("No log4j configuration resource found: " + log4jConfiguration); } else { org.apache.log4j.xml.DOMConfigurator.configure(configurationResourceUrl); } } catch (Exception e) { System.err.println("Could not initialize log4j logging system: " + e); } } void stop() { if (server != null) { try { server.stop(); } catch (Exception e) { throw new RuntimeException(e); } } } public static void main(String [] args) throws Exception { final DcsApp dcs = new DcsApp("dcs"); ParserProperties p = ParserProperties.defaults(); p.withUsageWidth(80); final CmdLineParser parser = new CmdLineParser(dcs, p); try { parser.parseArgument(args); } catch (CmdLineException e) { System.out.print("Usage: " + dcs.appName); parser.printSingleLineUsage(System.out); System.out.println(); parser.printUsage(System.out); System.out.println("\n" + e.getMessage()); return; } try { dcs.start(); } catch (Exception e) { dcs.log.error("Startup failure: " + e.getClass().getSimpleName() + ": " + e.getMessage()); } } }