From d7c5ad7d6263fd1baf9bfdbaa4c50b70ef2fbdb2 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Tue, 8 Jun 2010 08:22:05 +0200 Subject: reverted folder structure change for better mergeing with upstream --- trunk/infrastructure/net.appjet.oui/main.scala | 386 +++++++++++++++++++++++++ 1 file changed, 386 insertions(+) create mode 100644 trunk/infrastructure/net.appjet.oui/main.scala (limited to 'trunk/infrastructure/net.appjet.oui/main.scala') diff --git a/trunk/infrastructure/net.appjet.oui/main.scala b/trunk/infrastructure/net.appjet.oui/main.scala new file mode 100644 index 0000000..42cd268 --- /dev/null +++ b/trunk/infrastructure/net.appjet.oui/main.scala @@ -0,0 +1,386 @@ +/** + * Copyright 2009 Google 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 net.appjet.oui; + +import net.appjet.bodylock.{BodyLock, Executable}; + +import java.io.File; +import java.util.{Properties, Date}; +import java.lang.annotation.Annotation; +import java.text.SimpleDateFormat; + +import scala.collection.mutable.{HashMap, SynchronizedMap, HashSet}; +import scala.collection.jcl.{IterableWrapper, Conversions}; + +import org.mortbay.thread.QueuedThreadPool; +import org.mortbay.jetty.servlet.{Context, HashSessionIdManager, FilterHolder, ServletHolder}; +import org.mortbay.jetty.handler.{HandlerCollection, RequestLogHandler, HandlerList}; +import org.mortbay.jetty.{Server, NCSARequestLog, Request, Response}; +import org.mortbay.servlet.GzipFilter; + +// removed due to license restrictions +// import com.oreilly.servlet.MultipartFilter; + +import net.appjet.common.util.{BetterFile, HttpServletRequestFactory}; +import net.appjet.common.cli._; +import net.appjet.bodylock.JSCompileException; + +import Util.enumerationToRichEnumeration; + +object main { + val startTime = new java.util.Date(); + + def quit(status: Int) { + java.lang.Runtime.getRuntime().halt(status); + } + + def setupFilesystem() { + val logdir = new File(config.logDir+"/backend/access"); + if (! logdir.isDirectory()) + if (! logdir.mkdirs()) + quit(1); + } + + val options = + for (m <- config.allProperties if (m.getAnnotation(classOf[ConfigParam]) != null)) yield { + val cp = m.getAnnotation(classOf[ConfigParam]) + new CliOption(m.getName(), cp.value(), if (cp.argName().length > 0) Some(cp.argName()) else None); + } + + def printUsage() { + println("\n--------------------------------------------------------------------------------"); + println("usage:"); + println((new CliParser(options)).usage); + println("--------------------------------------------------------------------------------\n"); + } + + def extractOptions(args: Array[String]) { + val parser = new CliParser(options); + val opts = + try { + parser.parseOptions(args)._1; + } catch { + case e: ParseException => { + println("error: "+e.getMessage()); + printUsage(); + System.exit(1); + null; + } + } + if (opts.contains("configFile")) { + val p = new Properties(); + p.load(new java.io.FileInputStream(opts("configFile"))); + extractOptions(p); + } + for ((k, v) <- opts) { + config.values(k) = v; + } + } + + def extractOptions(props: Properties) { + for (k <- for (o <- props.propertyNames()) yield o.asInstanceOf[String]) { + config.values(k) = props.getProperty(k); + } + } + + val startupExecutable = (new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onstartup.js"))).executable; + def runOnStartup() { + execution.runOutOfBand(startupExecutable, "Startup", None, { error => + error match { + case e: JSCompileException => { } + case e: Throwable => { e.printStackTrace(); } + case (sc: Int, msg: String) => { println(msg); } + case x => println(x); + } + System.exit(1); + }); + } + + lazy val shutdownExecutable = (new FixedDiskLibrary(new SpecialJarOrNotFile(config.ajstdlibHome, "onshutdown.js"))).executable; + def runOnShutdown() { + execution.runOutOfBand(shutdownExecutable, "Shutdown", None, { error => + error match { + case e: JSCompileException => { } + case e: Throwable => { } + case (sc: Int, msg: String) => { println(msg); } + case x => println(x); + } + }); + } + + def runOnSars(q: String) = { + val ec = execution.runOutOfBand(execution.sarsExecutable, "SARS", Some(Map("sarsRequest" -> q)), { error => + error match { + case e: JSCompileException => { throw e; } + case e: Throwable => { exceptionlog(e); throw e; } + case (sc: Int, msg: String) => { println(msg); throw new RuntimeException(""+sc+": "+msg) } + case x => { println(x); throw new RuntimeException(x.toString()) } + } + }); + ec.attributes.get("sarsResponse").map(_.toString()); + } + + def stfu() { + System.setProperty("org.mortbay.log.class", "net.appjet.oui.STFULogger"); + System.setProperty("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog"); + System.setProperty("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "OFF"); + } + var server: Server = null; + var sarsServer: net.appjet.common.sars.SarsServer = null; + + var loggers = new HashSet[GenericLogger]; + def main(args: Array[String]) { + val etherpadProperties = getClass.getResource("/etherpad.properties"); + if (etherpadProperties != null) { + val p = new Properties(); + p.load(etherpadProperties.openStream); + extractOptions(p); + } + extractOptions(args); + + if (! config.verbose) + stfu(); + setupFilesystem(); + if (config.devMode) + config.print; + if (config.profile) + profiler.start(); + if (config.listenMonitoring != "0:0") + monitoring.startMonitoringServer(); + + // this needs a better place. + if (config.devMode) + BodyLock.map = Some(new HashMap[String, String] with SynchronizedMap[String, String]); + + server = new Server(); + if (config.maxThreads > 0) + server.setThreadPool(new QueuedThreadPool(config.maxThreads)); + else + server.setThreadPool(new QueuedThreadPool()); + // set up socket connectors + val nioconnector = new CometSelectChannelConnector; + var sslconnector: CometSslSelectChannelConnector = null; + nioconnector.setPort(config.listenPort); + if (config.listenHost.length > 0) + nioconnector.setHost(config.listenHost); + if (config.listenSecurePort == 0) { + server.setConnectors(Array(nioconnector)); + } else { + sslconnector = new CometSslSelectChannelConnector; + sslconnector.setPort(config.listenSecurePort); + if (config.listenSecureHost.length > 0) + sslconnector.setHost(config.listenSecureHost); + if (! config.sslKeyStore_isSet) { + val url = getClass.getResource("/mirror/snakeoil-ssl-cert"); + if (url != null) + sslconnector.setKeystore(url.toString()); + else + sslconnector.setKeystore(config.sslKeyStore); + } else { + sslconnector.setKeystore(config.sslKeyStore); + } + sslconnector.setPassword(config.sslStorePassword); + sslconnector.setKeyPassword(config.sslKeyPassword); + sslconnector.setTrustPassword(config.sslStorePassword); + sslconnector.setExcludeCipherSuites(Array[String]( + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + "SSL_RSA_WITH_NULL_MD5", + "SSL_RSA_WITH_NULL_SHA", + "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", + "SSL_DH_anon_WITH_DES_CBC_SHA", + "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", + "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA")); + server.setConnectors(Array(nioconnector, sslconnector)); + } + + // set up Context and Servlet + val handler = new Context(server, "/", Context.NO_SESSIONS | Context.NO_SECURITY); + handler.addServlet(new ServletHolder(new OuiServlet), "/"); + +// val filterHolder = new FilterHolder(new MultipartFilter()); +// filterHolder.setInitParameter("uploadDir", System.getProperty("java.io.tmpdir")); +// handler.addFilter(filterHolder, "/*", 1); + + global.context = handler; + + // set up apache-style logging + val requestLogHandler = new RequestLogHandler(); + val requestLog = new NCSARequestLog(config.logDir+"/backend/access/access-yyyy_mm_dd.request.log") { + override def log(req: Request, res: Response) { + try { + if (config.devMode || config.specialDebug) + super.log(req, res); + else if (res.getStatus() != 200 || config.transportPrefix == null || ! req.getRequestURI().startsWith(config.transportPrefix)) + super.log(req, res); + val d = new Date(); + appstats.stati.foreach(_(if (res.getStatus() < 0) 404 else res.getStatus()).hit(d)); + } catch { + case e => { exceptionlog("Error writing to log?"); exceptionlog(e); } + } + } + }; + requestLog.setRetainDays(365); + requestLog.setAppend(true); + requestLog.setExtended(true); + requestLog.setLogServer(true); + requestLog.setLogLatency(true); + requestLog.setLogTimeZone("PST"); + requestLogHandler.setRequestLog(requestLog); + + // set handlers with server + val businessHandlers = new HandlerList(); + businessHandlers.setHandlers(Array(handler)); + val allHandlers = new HandlerCollection(); + allHandlers.setHandlers(Array(businessHandlers, requestLogHandler)); + server.setHandler(allHandlers); + + // fix slow startup bug + server.setSessionIdManager(new HashSessionIdManager(new java.util.Random())); + + // run the onStartup script. + runOnStartup(); + + // preload some runners, if necessary. + if (config.preloadRunners > 0) { + val b = new java.util.concurrent.CountDownLatch(config.preloadRunners); + for (i <- 0 until config.preloadRunners) + (new Thread { + ScopeReuseManager.freeRunner(ScopeReuseManager.newRunner); + b.countDown(); + }).start(); + while (b.getCount() > 0) { + b.await(); + } + println("Preloaded "+config.preloadRunners+" runners."); + } + + // start SARS server. + if (config.listenSarsPort > 0) { + try { + import net.appjet.common.sars._; + sarsServer = new SarsServer(config.sarsAuthKey, + new SarsMessageHandler { override def handle(q: String) = runOnSars(q) }, + if (config.listenSarsHost.length > 0) Some(config.listenSarsHost) else None, + config.listenSarsPort); + sarsServer.daemon = true; + sarsServer.start(); + } catch { + case e: java.net.SocketException => { + println("SARS: A socket exception occurred: "+e.getMessage()+" on SARS server at "+config.listenSarsHost+":"+config.listenSarsPort); + java.lang.Runtime.getRuntime().halt(1); + } + } + } + + // start server + java.lang.Runtime.getRuntime().addShutdownHook(new Thread() { + override def run() { + val df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ"); + def printts(str: String) { + println("["+df.format(new Date())+"]: "+str); + } + printts("Shutting down..."); + handler.setShutdown(true); + Thread.sleep(if (config.devMode) 500 else 3000); + printts("...done, running onshutdown."); + runOnShutdown(); + printts("...done, stopping server."); + server.stop(); + server.join(); + printts("...done, flushing logs."); + for (l <- loggers) { l.flush(); l.close(); } + printts("...done."); + } + }); + + def socketError(c: org.mortbay.jetty.Connector, e: java.net.SocketException) { + var msg = e.getMessage(); + println("SOCKET ERROR: "+msg+" - "+(c match { + case null => "(unknown socket)"; + case x => { + (x.getHost() match { + case null => "localhost"; + case y => y; + })+":"+x.getPort(); + } + })); + if (msg.contains("Address already in use")) { + println("Did you make sure that ports "+config.listenPort+" and "+config.listenSecurePort+" are not in use?"); + } + if (msg.contains("Permission denied")) { + println("Perhaps you need to run as the root user or as an Administrator?"); + } + } + + var c: org.mortbay.jetty.Connector = null; + + try { + c = nioconnector; + c.open(); + if (sslconnector != null) { + c = sslconnector; + c.open(); + } + c = null; + allHandlers.start(); + server.start(); + } catch { + case e: java.net.SocketException => { + socketError(c, e); + java.lang.Runtime.getRuntime().halt(1); + } + case e: org.mortbay.util.MultiException => { + println("SERVER ERROR: Couldn't start server; multiple errors."); + for (i <- new IterableWrapper[Throwable] { override val underlying = e.getThrowables.asInstanceOf[java.util.List[Throwable]] }) { + i match { + case se: java.net.SocketException => { + socketError(c, se); + } + case e => + println("SERVER ERROR: Couldn't start server: "+i.getMessage()); + } + } + java.lang.Runtime.getRuntime().halt(1); + } + case e => { + println("SERVER ERROR: Couldn't start server: "+e.getMessage()); + java.lang.Runtime.getRuntime().halt(1); + } + } + + println("HTTP server listening on http://"+ + (if (config.listenHost.length > 0) config.listenHost else "localhost")+ + ":"+config.listenPort+"/"); + if (config.listenSecurePort > 0) + println("HTTPS server listening on https://"+ + (if (config.listenSecureHost.length > 0) config.listenSecureHost else "localhost")+ + ":"+config.listenSecurePort+"/"); + if (config.listenSarsPort > 0) + println("SARS server listening on "+ + (if (config.listenSarsHost.length > 0) config.listenSarsHost else "localhost")+ + ":"+config.listenSarsPort); + } +} -- cgit v1.2.3