blob: 87e52cbc6716e83549d181807ddef929da946642 [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.uniffle.common.web;
import java.io.FileNotFoundException;
import java.net.BindException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.hbase.thirdparty.org.glassfish.jersey.server.ServerProperties;
import org.apache.hbase.thirdparty.org.glassfish.jersey.servlet.ServletContainer;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.uniffle.common.config.RssBaseConf;
import org.apache.uniffle.common.util.ExitUtils;
import org.apache.uniffle.common.util.ThreadUtils;
public class JettyServer {
private static final Logger LOG = LoggerFactory.getLogger(JettyServer.class);
private Server server;
private ServletContextHandler servletContextHandler;
private int httpPort;
private ServletHolder servletHolder;
private Set<String> reourcePackages = new HashSet<>();
public JettyServer(RssBaseConf conf) throws FileNotFoundException {
createServer(conf);
}
public void createServer(RssBaseConf conf) throws FileNotFoundException {
httpPort = conf.getInteger(RssBaseConf.JETTY_HTTP_PORT);
ExecutorThreadPool threadPool = createThreadPool(conf);
server = new Server(threadPool);
server.setStopAtShutdown(true);
server.setStopTimeout(conf.getLong(RssBaseConf.JETTY_STOP_TIMEOUT));
server.addBean(new ScheduledExecutorScheduler("jetty-thread-pool", true));
HttpConfiguration httpConfig = new HttpConfiguration();
addHttpConnector(
conf.getInteger(RssBaseConf.JETTY_HTTP_PORT),
httpConfig,
conf.getLong(RssBaseConf.JETTY_HTTP_IDLE_TIMEOUT));
setRootServletHandler();
if (conf.getBoolean(RssBaseConf.JETTY_SSL_ENABLE)) {
addHttpsConnector(httpConfig, conf);
}
}
private ExecutorThreadPool createThreadPool(RssBaseConf conf) {
int corePoolSize = conf.getInteger(RssBaseConf.JETTY_CORE_POOL_SIZE);
int maxPoolSize = conf.getInteger(RssBaseConf.JETTY_MAX_POOL_SIZE);
ExecutorThreadPool pool =
new ExecutorThreadPool(
new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
ThreadUtils.getThreadFactory("Jetty")));
return pool;
}
private void addHttpConnector(int port, HttpConfiguration httpConfig, long idleTimeout) {
ServerConnector httpConnector =
new ServerConnector(server, new HttpConnectionFactory(httpConfig));
httpConnector.setPort(port);
httpConnector.setIdleTimeout(idleTimeout);
server.addConnector(httpConnector);
}
private void addHttpsConnector(HttpConfiguration httpConfig, RssBaseConf conf)
throws FileNotFoundException {
LOG.info("Create https connector");
Path keystorePath = Paths.get(conf.get(RssBaseConf.JETTY_SSL_KEYSTORE_PATH)).toAbsolutePath();
if (!Files.exists(keystorePath)) {
throw new FileNotFoundException(keystorePath.toString());
}
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath(keystorePath.toString());
sslContextFactory.setKeyStorePassword(conf.get(RssBaseConf.JETTY_SSL_KEYSTORE_PASSWORD));
sslContextFactory.setKeyManagerPassword(conf.get(RssBaseConf.JETTY_SSL_KEYMANAGER_PASSWORD));
sslContextFactory.setTrustStorePath(keystorePath.toString());
sslContextFactory.setTrustStorePassword(conf.get(RssBaseConf.JETTY_SSL_TRUSTSTORE_PASSWORD));
int securePort = conf.getInteger(RssBaseConf.JETTY_HTTPS_PORT);
httpConfig.setSecurePort(securePort);
HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
httpsConfig.addCustomizer(new SecureRequestCustomizer());
ServerConnector sslConnector =
new ServerConnector(
server,
new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(httpsConfig));
sslConnector.setPort(securePort);
server.addConnector(sslConnector);
}
private void setRootServletHandler() {
servletContextHandler = new ServletContextHandler();
servletContextHandler.setContextPath("/");
server.setHandler(servletContextHandler);
servletHolder = servletContextHandler.addServlet(ServletContainer.class, "/*");
}
public void addResourcePackages(String... packages) {
reourcePackages.addAll(Arrays.asList(packages));
servletHolder.setInitParameter(
ServerProperties.PROVIDER_PACKAGES, String.join(",", reourcePackages));
}
public void registerInstance(Class<?> clazz, Object instance) {
registerInstance(clazz.getCanonicalName(), instance);
}
public void registerInstance(String name, Object instance) {
servletContextHandler.setAttribute(name, instance);
}
public Server getServer() {
return this.server;
}
public void start() throws Exception {
try {
server.start();
} catch (BindException e) {
ExitUtils.terminate(1, "Fail to start jetty http server", e, LOG);
}
LOG.info("Jetty http server started, listening on port {}", httpPort);
}
public void stop() throws Exception {
server.stop();
}
}