/* * Copyright 2013 Netflix, 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 com.netflix.suro.server; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Singleton; import com.google.inject.servlet.GuiceFilter; import com.google.inject.servlet.GuiceServletContextListener; import com.google.inject.servlet.ServletModule; import com.netflix.suro.input.thrift.ServerConfig; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.ServletContextHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Embedded Jetty for status page * * @author jbae */ @Singleton public class StatusServer { static Logger log = LoggerFactory.getLogger(StatusServer.class); public static ServletModule createJerseyServletModule() { return new ServletModule() { @Override protected void configureServlets() { bind(HealthCheck.class); bind(SinkStat.class); bind(GuiceContainer.class).asEagerSingleton(); serve("/*").with(GuiceContainer.class); } }; } private final ExecutorService executor = Executors.newSingleThreadExecutor(); private final ServerConfig config; private final Injector injector; private final CountDownLatch startLatch = new CountDownLatch(1); @Inject public StatusServer(ServerConfig config, Injector injector) { this.injector = injector; this.config = config; } public void waitUntilStarted() throws InterruptedException { startLatch.await(); } public void start() { log.info("StatusServer starting"); executor.submit(new Runnable() { @Override public void run() { Server server = new Server(config.getStatusServerPort()); log.info("Starting status server on " + config.getStatusServerPort()); // Create a servlet context and add the jersey servlet. ServletContextHandler sch = new ServletContextHandler(server, "/"); // Add our Guice listener that includes our bindings sch.addEventListener(new GuiceServletContextListener() { @Override protected Injector getInjector() { return injector; } }); // Then add GuiceFilter and configure the server to // reroute all requests through this filter. sch.addFilter(GuiceFilter.class, "/*", null); // Must add DefaultServlet for embedded Jetty. // Failing to do this will cause 404 errors. // This is not needed if web.xml is used instead. sch.addServlet(DefaultServlet.class, "/"); // Start the server try { server.start(); startLatch.countDown(); server.join(); } catch (InterruptedException ie) { log.info("Interrupted to shutdown status server:"); } catch (Exception e) { log.error("Failed to start status server", e); } finally { try { server.stop(); log.info("StatusServer was shutdown"); } catch (Exception e) { log.error("Failed to join status server", e); } } } }); } public void shutdown() { try { log.info("StatusServer shutting down"); executor.shutdownNow(); } catch (Exception e) { //ignore exceptions while shutdown log.error("Exception while shutting down: " + e.getMessage(), e); } } }