Skip to content

Instantly share code, notes, and snippets.

@natros
Forked from ben-manes/HttpPort.java
Last active August 29, 2015 14:24
Show Gist options
  • Select an option

  • Save natros/a9f8eaba60e1e5de80b7 to your computer and use it in GitHub Desktop.

Select an option

Save natros/a9f8eaba60e1e5de80b7 to your computer and use it in GitHub Desktop.

Revisions

  1. @ben-manes ben-manes created this gist Jul 12, 2015.
    9 changes: 9 additions & 0 deletions HttpPort.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    /**
    * A qualifier for the server http port.
    *
    * @author [email protected] (Ben Manes)
    */
    @BindingAnnotation
    @Retention(RUNTIME)
    @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
    public @interface HttpPort {}
    9 changes: 9 additions & 0 deletions HttpsPort.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    /**
    * A qualifier for the server https port.
    *
    * @author [email protected] (Ben Manes)
    */
    @BindingAnnotation
    @Retention(RUNTIME)
    @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
    public @interface HttpsPort {}
    65 changes: 65 additions & 0 deletions JettyModule.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,65 @@
    /**
    * A module that configures the Jetty webserver.
    *
    * @author [email protected] (Ben Manes)
    */
    public final class JettyModule extends ServletModule {
    final Config config = ConfigFactory.load().getConfig(getClass().getPackage().getName());

    @Override
    protected void configureServlets() {
    configureAdminServlet();
    configureMetricsFilter();
    install(new MetricsModule());
    bind(Server.class).toProvider(ServerProvider.class);
    }

    @Provides @HttpPort
    OptionalInt providesHttpPort() {
    return config.hasPath("http_port")
    ? OptionalInt.of(config.getInt("http_port"))
    : OptionalInt.empty();
    }

    @Provides @HttpsPort
    OptionalInt providesHttpsPort() {
    return config.hasPath("https_port")
    ? OptionalInt.of(config.getInt("https_port"))
    : OptionalInt.empty();
    }

    private void configureMetricsFilter() {
    filter("/*").through(InstrumentedFilter.class);
    bind(InstrumentedFilter.class).in(Singleton.class);

    Multibinder.newSetBinder(binder(), ServletContextListener.class)
    .addBinding().toInstance(new InstrumentedFilterContextListener() {
    @Override protected MetricRegistry getMetricRegistry() {
    return SharedRegistry.metricRegistry();
    }
    });
    Multibinder.newSetBinder(binder(), ServletContextListener.class)
    .addBinding().toInstance(new HealthCheckServlet.ContextListener() {
    @Override protected HealthCheckRegistry getHealthCheckRegistry() {
    return SharedRegistry.healthCheckRegistry();
    }
    });
    Multibinder.newSetBinder(binder(), ServletContextListener.class)
    .addBinding().toInstance(new MetricsServlet.ContextListener() {
    @Override protected MetricRegistry getMetricRegistry() {
    return SharedRegistry.metricRegistry();
    }
    });
    }

    private void configureAdminServlet() {
    bind(AdminServlet.class).asEagerSingleton();

    Map<String, String> initParams = ImmutableMap.of(
    "healthcheck-uri", AdminServlet.DEFAULT_HEALTHCHECK_URI,
    "threads-uri", AdminServlet.DEFAULT_THREADS_URI,
    "metrics-uri",AdminServlet.DEFAULT_METRICS_URI,
    "ping-uri", AdminServlet.DEFAULT_PING_URI);
    serve("/admin/*").with(AdminServlet.class, initParams);
    }
    }
    106 changes: 106 additions & 0 deletions ServerProvider.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,106 @@
    /**
    * Provides a fully configured Jetty server.
    *
    * @author [email protected] (Ben Manes)
    */
    final class ServerProvider implements Provider<Server> {
    private final Config config = ConfigFactory.load().getConfig(getClass().getPackage().getName());
    private final Set<ServletContextListener> listeners;
    private final OptionalInt httpsPort;
    private final OptionalInt httpPort;

    @Inject
    public ServerProvider(@HttpPort OptionalInt httpPort, @HttpsPort OptionalInt httpsPort,
    Set<ServletContextListener> listeners) {
    this.listeners = listeners;
    this.httpsPort = httpsPort;
    this.httpPort = httpPort;
    }

    @Override
    public Server get() {
    Server server = new Server(new InstrumentedQueuedThreadPool(SharedRegistry.metricRegistry()));
    addConnectors(server);
    addHandler(server);
    configure(server);
    return server;
    }

    private void configure(Server server) {
    server.setRequestLog(new Slf4jRequestLog());
    }

    private void addHandler(Server server) {
    InstrumentedHandler instrumented = new InstrumentedHandler(SharedRegistry.metricRegistry());
    ServletContextHandler handler = new ServletContextHandler(instrumented, "/");
    handler.addFilter(GuiceFilter.class, "/*", null);
    handler.addServlet(DefaultServlet.class, "/");
    for (ServletContextListener listener : listeners) {
    handler.addEventListener(listener);
    }
    server.setHandler(instrumented);
    }

    private void addConnectors(Server server) {
    checkState(httpPort.isPresent() || httpsPort.isPresent(), "No http/s port specified");
    List<Connector> connectors = new ArrayList<>();
    String host = config.hasPath("host") ? config.getString("host") : null;
    if (httpPort.isPresent()) {
    connectors.add(newHttpConnector(server, host));
    }
    if (httpsPort.isPresent()) {
    connectors.add(newHttpsConnector(server, host));
    }
    server.setConnectors(connectors.toArray(new Connector[connectors.size()]));
    }

    private ServerConnector newHttpConnector(Server server, String host) {
    HttpConfiguration httpConfig = new HttpConfiguration();
    if (httpsPort.isPresent()) {
    httpConfig.setSecurePort(httpsPort.getAsInt());
    }
    ServerConnector http = new ServerConnector(server,
    new ProtocolAwareInstrumentedConnectionFactory(
    new HttpConnectionFactory(httpConfig), "http.connection"));
    http.setPort(httpPort.getAsInt());
    http.setHost(host);
    return http;
    }

    private ServerConnector newHttpsConnector(Server server, String host) {
    HttpConfiguration httpsConfig = new HttpConfiguration();
    httpsConfig.addCustomizer(new SecureRequestCustomizer());
    ServerConnector https = new ServerConnector(server,
    new SslConnectionFactory(newSslContextFactory(), "http/1.1"),
    new ProtocolAwareInstrumentedConnectionFactory(
    new HttpConnectionFactory(httpsConfig), "https.connection"));
    https.setPort(httpsPort.getAsInt());
    https.setHost(host);
    return https;
    }

    private SslContextFactory newSslContextFactory() {
    SslContextFactory sslContextFactory = new SslContextFactory();
    sslContextFactory.setKeyStorePath(config.getString("key_store.path"));
    sslContextFactory.setKeyStorePassword(config.getString("key_store.password"));
    if (config.hasPath("key_store.manager_password")) {
    sslContextFactory.setKeyManagerPassword(config.getString("key_store.manager_password"));
    }
    return sslContextFactory;
    }

    private static final class ProtocolAwareInstrumentedConnectionFactory
    extends InstrumentedConnectionFactory {
    final ConnectionFactory delegate;

    ProtocolAwareInstrumentedConnectionFactory(ConnectionFactory delegate, String timerName) {
    super(delegate, SharedRegistry.metricRegistry().timer(timerName));
    this.delegate = delegate;
    }

    @Override
    public List<String> getProtocols() {
    return delegate.getProtocols();
    }
    }
    }