blob: 384972262e2280228d8cd9cfcf730250950aa68d [file] [log] [blame]
/*
* 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.samza.coordinator.server;
import javax.servlet.Servlet
import org.apache.samza.SamzaException
import org.eclipse.jetty.server.NetworkConnector
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.DefaultServlet
import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.servlet.ServletHolder
import java.net.URL
import org.apache.samza.util.{Util, Logging}
/**
* <p>A Jetty-based HTTP server. The server allows arbitrary servlets to be added
* with the addServlet() method. The server is configured to automatically
* serve static CSS and JS from the /css and /js directories if a
* resourceBasePath is specified.</p>
*/
class HttpServer(
/**
* All servlet paths will be served out of the rootPath. If rootPath is set
* to /foo, then all servlet paths will be served underneath /foo.
*/
rootPath: String = "/",
/**
* The port that Jetty should bind to. If set to 0, Jetty will bind to a
* dynamically allocated free port on the machine it's running on. The port
* can be retrieved by calling .getUrl.
*/
port: Int = 0,
/**
* If specified, tells Jetty where static resources are located inside
* WEB-INF. This allows HttpServer to serve arbitrary static files that are
* embedded in a JAR.
*/
resourceBasePath: String = null,
/**
* The SevletHolder to use for static file (CSS/JS) serving.
*/
defaultHolder: ServletHolder = new ServletHolder(classOf[DefaultServlet])) extends Logging {
var running = false
var servlets = Map[String, Servlet]()
val server = new Server(port)
val context = new ServletContextHandler(ServletContextHandler.SESSIONS)
defaultHolder.setName("default")
/**
* <p>
* Add a servlet to the Jetty container. Path can be wild-carded (e.g. /\*
* or /foo/\*), and is relative to the rootPath specified in the constructor.
* </p>
*
* <p>
* Servlets with path /bar/\* and rootPath /foo will result in a location of
* http://localhost/foo/bar.
* </p>
*/
def addServlet(path: String, servlet: Servlet) {
debug("Adding servlet %s to path %s" format (servlet, path))
servlets += path -> servlet
}
/**
* Start the Jetty server, and begin serving content.
*/
def start {
debug("Starting server with rootPath=%s port=%s resourceBasePath=%s" format (rootPath, port, resourceBasePath))
context.setContextPath(rootPath)
server.setHandler(context)
context.addServlet(defaultHolder, "/css/*")
context.addServlet(defaultHolder, "/js/*")
// TODO This is where you'd add Hadoop's Kerberos security filters.
// context.addFilter(classOf[YourApplicationEndpointFilter], "/*", 0)
if (resourceBasePath != null) {
context.setResourceBase(getClass.getClassLoader.getResource(resourceBasePath).toExternalForm())
}
servlets.foreach {
case (path, servlet) =>
context.addServlet(new ServletHolder(servlet), path);
}
debug("Starting HttpServer.")
server.start()
running = true
info("Started HttpServer on: %s" format getUrl)
}
/**
* Shutdown the Jetty server.
*/
def stop {
running = false
debug("Stopping server")
context.stop()
server.stop()
info("Stopped server")
}
/**
* Returns the URL for the root of the HTTP server. This method
*/
def getUrl = {
if (running) {
val runningPort = server.getConnectors()(0).asInstanceOf[NetworkConnector].getLocalPort()
new URL("http://" + Util.getLocalHost.getHostName + ":" + runningPort + rootPath)
} else {
throw new SamzaException("HttpServer is not currently running, so URLs are not available for it.")
}
}
}