static Server makeAndInitializeServer()

in server/src/main/java/org/apache/druid/server/initialization/jetty/JettyServerModule.java [185:489]


  static Server makeAndInitializeServer(
      Injector injector,
      Lifecycle lifecycle,
      DruidNode node,
      ServerConfig config,
      TLSServerConfig tlsServerConfig,
      Binding<SslContextFactory.Server> sslContextFactoryBinding,
      TLSCertificateChecker certificateChecker
  )
  {
    // adjusting to make config.getNumThreads() mean, "number of threads
    // that concurrently handle the requests".
    int numServerThreads = config.getNumThreads() + getMaxJettyAcceptorsSelectorsNum(node);

    final QueuedThreadPool threadPool;
    if (config.getQueueSize() == Integer.MAX_VALUE) {
      threadPool = new QueuedThreadPool();
      threadPool.setMinThreads(numServerThreads);
      threadPool.setMaxThreads(numServerThreads);
    } else {
      threadPool = new QueuedThreadPool(
          numServerThreads,
          numServerThreads,
          60000, // same default is used in other case when threadPool = new QueuedThreadPool()
          new LinkedBlockingQueue<>(config.getQueueSize())
      );
    }

    threadPool.setDaemon(true);
    jettyServerThreadPool = threadPool;

    final Server server = new Server(threadPool);

    // Without this bean set, the default ScheduledExecutorScheduler runs as non-daemon, causing lifecycle hooks to fail
    // to fire on main exit. Related bug: https://github.com/apache/druid/pull/1627
    server.addBean(new ScheduledExecutorScheduler("JettyScheduler", true), true);

    final List<ServerConnector> serverConnectors = new ArrayList<>();

    if (node.isEnablePlaintextPort()) {
      log.info("Creating http connector with port [%d]", node.getPlaintextPort());
      HttpConfiguration httpConfiguration = new HttpConfiguration();
      if (config.isEnableForwardedRequestCustomizer()) {
        httpConfiguration.addCustomizer(new ForwardedRequestCustomizer());
      }

      httpConfiguration.setRequestHeaderSize(config.getMaxRequestHeaderSize());
      httpConfiguration.setSendServerVersion(false);
      final ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
      if (node.isBindOnHost()) {
        connector.setHost(node.getHost());
      }
      connector.setPort(node.getPlaintextPort());
      serverConnectors.add(connector);
    }

    final SslContextFactory.Server sslContextFactory;

    if (node.isEnableTlsPort()) {
      log.info("Creating https connector with port [%d]", node.getTlsPort());
      if (sslContextFactoryBinding == null) {
        // Never trust all certificates by default
        sslContextFactory = new IdentityCheckOverrideSslContextFactory(tlsServerConfig, certificateChecker);

        sslContextFactory.setKeyStorePath(tlsServerConfig.getKeyStorePath());
        sslContextFactory.setKeyStoreType(tlsServerConfig.getKeyStoreType());
        sslContextFactory.setKeyStorePassword(tlsServerConfig.getKeyStorePasswordProvider().getPassword());
        sslContextFactory.setCertAlias(tlsServerConfig.getCertAlias());
        sslContextFactory.setKeyManagerFactoryAlgorithm(tlsServerConfig.getKeyManagerFactoryAlgorithm() == null
                                                        ? KeyManagerFactory.getDefaultAlgorithm()
                                                        : tlsServerConfig.getKeyManagerFactoryAlgorithm());
        sslContextFactory.setKeyManagerPassword(tlsServerConfig.getKeyManagerPasswordProvider() == null ?
                                                null : tlsServerConfig.getKeyManagerPasswordProvider().getPassword());
        if (tlsServerConfig.getIncludeCipherSuites() != null) {
          sslContextFactory.setIncludeCipherSuites(
              tlsServerConfig.getIncludeCipherSuites().toArray(new String[0]));
        }
        if (tlsServerConfig.getExcludeCipherSuites() != null) {
          sslContextFactory.setExcludeCipherSuites(
              tlsServerConfig.getExcludeCipherSuites().toArray(new String[0]));
        }
        if (tlsServerConfig.getIncludeProtocols() != null) {
          sslContextFactory.setIncludeProtocols(
              tlsServerConfig.getIncludeProtocols().toArray(new String[0]));
        }
        if (tlsServerConfig.getExcludeProtocols() != null) {
          sslContextFactory.setExcludeProtocols(
              tlsServerConfig.getExcludeProtocols().toArray(new String[0]));
        }

        sslContextFactory.setNeedClientAuth(tlsServerConfig.isRequireClientCertificate());
        sslContextFactory.setWantClientAuth(tlsServerConfig.isRequestClientCertificate());
        if (tlsServerConfig.isRequireClientCertificate() || tlsServerConfig.isRequestClientCertificate()) {
          if (tlsServerConfig.getCrlPath() != null) {
            // setValidatePeerCerts is used just to enable revocation checking using a static CRL file.
            // Certificate validation is always performed when client certificates are required.
            sslContextFactory.setValidatePeerCerts(true);
            sslContextFactory.setCrlPath(tlsServerConfig.getCrlPath());
          }
          if (tlsServerConfig.isValidateHostnames()) {
            sslContextFactory.setEndpointIdentificationAlgorithm("HTTPS");
          }
          if (tlsServerConfig.getTrustStorePath() != null) {
            sslContextFactory.setTrustStorePath(tlsServerConfig.getTrustStorePath());
            sslContextFactory.setTrustStoreType(
                tlsServerConfig.getTrustStoreType() == null
                ? KeyStore.getDefaultType()
                : tlsServerConfig.getTrustStoreType()
            );
            sslContextFactory.setTrustManagerFactoryAlgorithm(
                tlsServerConfig.getTrustStoreAlgorithm() == null
                ? TrustManagerFactory.getDefaultAlgorithm()
                : tlsServerConfig.getTrustStoreAlgorithm()
            );
            sslContextFactory.setTrustStorePassword(
                tlsServerConfig.getTrustStorePasswordProvider() == null
                ? null
                : tlsServerConfig.getTrustStorePasswordProvider().getPassword()
            );
          }
        }
      } else {
        sslContextFactory = sslContextFactoryBinding.getProvider().get();
      }

      final HttpConfiguration httpsConfiguration = new HttpConfiguration();
      if (config.isEnableForwardedRequestCustomizer()) {
        httpsConfiguration.addCustomizer(new ForwardedRequestCustomizer());
      }
      httpsConfiguration.setSecureScheme("https");
      httpsConfiguration.setSecurePort(node.getTlsPort());
      httpsConfiguration.addCustomizer(new SecureRequestCustomizer());
      httpsConfiguration.setRequestHeaderSize(config.getMaxRequestHeaderSize());
      httpsConfiguration.setSendServerVersion(false);
      final ServerConnector connector = new ServerConnector(
          server,
          new SslConnectionFactory(sslContextFactory, HTTP_1_1_STRING),
          new HttpConnectionFactory(httpsConfiguration)
      );
      if (node.isBindOnHost()) {
        connector.setHost(node.getHost());
      }
      connector.setPort(node.getTlsPort());
      serverConnectors.add(connector);
      if (tlsServerConfig.isReloadSslContext()) {
        KeyStoreScanner keyStoreScanner = new KeyStoreScanner(sslContextFactory);
        keyStoreScanner.setScanInterval(tlsServerConfig.getReloadSslContextSeconds());
        server.addBean(keyStoreScanner);
      }
    } else {
      sslContextFactory = null;
    }

    final ServerConnector[] connectors = new ServerConnector[serverConnectors.size()];
    int index = 0;
    for (ServerConnector connector : serverConnectors) {
      connectors[index++] = connector;
      connector.setIdleTimeout(Ints.checkedCast(config.getMaxIdleTime().toStandardDuration().getMillis()));
      // workaround suggested in -
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=435322#c66 for jetty half open connection issues during failovers
      connector.setAcceptorPriorityDelta(-1);
      connector.setAcceptQueueSize(getTCPAcceptQueueSize());

      List<ConnectionFactory> monitoredConnFactories = new ArrayList<>();
      for (ConnectionFactory cf : connector.getConnectionFactories()) {
        // we only want to monitor the first connection factory, since it will pass the connection to subsequent
        // connection factories (in this case HTTP/1.1 after the connection is unencrypted for SSL)
        if (cf.getProtocol().equals(connector.getDefaultProtocol())) {
          monitoredConnFactories.add(new JettyMonitoringConnectionFactory(cf, ACTIVE_CONNECTIONS));
        } else {
          monitoredConnFactories.add(cf);
        }
      }
      connector.setConnectionFactories(monitoredConnFactories);
    }

    server.setConnectors(connectors);
    final long gracefulStop = config.getGracefulShutdownTimeout().toStandardDuration().getMillis();
    if (gracefulStop > 0) {
      server.setStopTimeout(gracefulStop);
    }
    server.addLifeCycleListener(new LifeCycle.Listener()
    {
      @Override
      public void lifeCycleStarting(LifeCycle event)
      {
        log.debug("Jetty lifecycle starting [%s]", event.getClass());
      }

      @Override
      public void lifeCycleStarted(LifeCycle event)
      {
        log.debug("Jetty lifeycle started [%s]", event.getClass());
      }

      @Override
      public void lifeCycleFailure(LifeCycle event, Throwable cause)
      {
        log.error(cause, "Jetty lifecycle event failed [%s]", event.getClass());
      }

      @Override
      public void lifeCycleStopping(LifeCycle event)
      {
        log.debug("Jetty lifecycle stopping [%s]", event.getClass());
      }

      @Override
      public void lifeCycleStopped(LifeCycle event)
      {
        log.debug("Jetty lifecycle stopped [%s]", event.getClass());
      }
    });

    // initialize server
    JettyServerInitializer initializer = injector.getInstance(JettyServerInitializer.class);
    try {
      initializer.initialize(server, injector);
    }
    catch (Exception e) {
      throw new RE(e, "server initialization exception");
    }

    lifecycle.addHandler(
        new Lifecycle.Handler()
        {
          @Override
          public void start() throws Exception
          {
            log.debug("Starting Jetty Server...");
            server.start();
            if (node.isEnableTlsPort()) {
              // Perform validation
              Preconditions.checkNotNull(sslContextFactory);
              final SSLEngine sslEngine = sslContextFactory.newSSLEngine();
              if (sslEngine.getEnabledCipherSuites() == null || sslEngine.getEnabledCipherSuites().length == 0) {
                throw new ISE(
                    "No supported cipher suites found, supported suites [%s], configured suites include list: [%s] exclude list: [%s]",
                    Arrays.toString(sslEngine.getSupportedCipherSuites()),
                    tlsServerConfig.getIncludeCipherSuites(),
                    tlsServerConfig.getExcludeCipherSuites()
                );
              }
              if (sslEngine.getEnabledProtocols() == null || sslEngine.getEnabledProtocols().length == 0) {
                throw new ISE(
                    "No supported protocols found, supported protocols [%s], configured protocols include list: [%s] exclude list: [%s]",
                    Arrays.toString(sslEngine.getSupportedProtocols()),
                    tlsServerConfig.getIncludeProtocols(),
                    tlsServerConfig.getExcludeProtocols()
                );
              }
            }
          }

          @Override
          public void stop()
          {
            try {
              final long unannounceDelay = config.getUnannouncePropagationDelay().toStandardDuration().getMillis();
              if (unannounceDelay > 0) {
                log.info("Sleeping %s ms for unannouncement to propagate.", unannounceDelay);
                Thread.sleep(unannounceDelay);
              } else {
                log.debug("Skipping unannounce wait.");
              }
              log.debug("Stopping Jetty Server...");
              server.stop();
            }
            catch (InterruptedException e) {
              Thread.currentThread().interrupt();
              throw new RE(e, "Interrupted waiting for jetty shutdown.");
            }
            catch (Exception e) {
              log.warn(e, "Unable to stop Jetty server.");
            }
          }
        },
        Lifecycle.Stage.SERVER
    );

    if (!config.isShowDetailedJettyErrors()) {
      server.setErrorHandler(new ErrorHandler()
      {
        @Override
        public boolean isShowServlet()
        {
          return false;
        }

        @Override
        public void handle(
            String target,
            Request baseRequest,
            HttpServletRequest request,
            HttpServletResponse response
        ) throws IOException, ServletException
        {
          request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, null);
          super.handle(target, baseRequest, request, response);
        }
      });
    }

    return server;
  }