All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.turbospaces.jetty.JettyChannel Maven / Gradle / Ivy

The newest version!
package com.turbospaces.jetty;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.BlockingQueue;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.eclipse.jetty.io.ConnectionStatistics;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.context.SmartLifecycle;

import com.turbospaces.cfg.ApplicationProperties;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.binder.jetty.JettyConnectionMetrics;
import io.micrometer.core.instrument.binder.jetty.JettyServerThreadPoolMetrics;
import io.micrometer.core.instrument.binder.jetty.JettySslHandshakeMetrics;

public abstract class JettyChannel implements SmartLifecycle {
    public static final String WEB_XML = "WEB-INF/web.xml";

    private final Logger logger = LoggerFactory.getLogger(getClass());
    private final ApplicationProperties props;
    private final MeterRegistry meterRegistry;
    private final int port;
    private final ConnectionStatistics stats = new ConnectionStatistics();
    private final StatisticsHandler statsHandler = new StatisticsHandler();
    private final Set handlers = new HashSet<>();
    private ServerConnector connector;
    private boolean running;
    private Server jetty;

    protected JettyChannel(ApplicationProperties props, MeterRegistry meterRegistry, int port) {
        this.props = Objects.requireNonNull(props);
        this.meterRegistry = Objects.requireNonNull(meterRegistry);
        this.port = Objects.requireNonNull(port);
    }
    @Override
    public void start() {
        try {
            int maxWorkers = props.JETTY_POOL_MAX_SIZE.get();
            int minWorkers = props.JETTY_POOL_MIN_SIZE.get();
            int maxIdle = (int) props.JETTY_POOL_MAX_IDLE.get().toMillis();
            int queueCapacity = props.JETTY_POOL_QUEUE_MAX_SIZE.get();

            BlockingQueue queue = new BlockingArrayQueue<>(queueCapacity);
            QueuedThreadPool threadPool = new QueuedThreadPool(maxWorkers, minWorkers, maxIdle, queue);
            jetty = new Server(threadPool);

            createConnector();
            startServer();

            this.running = true;
        } catch (Exception err) {
            throw new BeanInitializationException(err.getMessage(), err);
        }
    }
    @Override
    public void stop() {
        try {
            if (Objects.nonNull(jetty)) {
                long connections = stats.getConnections();
                int requestsActive = statsHandler.getRequestsActive();
                logger.info("stopping jetty, active connections: {}, pending requests: {}...", connections, requestsActive);
                jetty.stop();

                //
                // just in case
                //
                QueuedThreadPool threadPool = (QueuedThreadPool) jetty.getServer().getThreadPool();
                threadPool.stop();

                this.running = false;
            }
        } catch (Exception err) {
            ExceptionUtils.wrapAndThrow(err);
        }
    }
    @Override
    public boolean isRunning() {
        return running;
    }
    public Server server() {
        return jetty;
    }
    public StatisticsHandler statsHandler() {
        return statsHandler;
    }
    public ConnectionStatistics connectorStats() {
        return stats;
    }
    protected void addHandler(ServletContextHandler handler) {
        handlers.add(handler);
    }
    protected void startServer() throws Exception {
        HandlerCollection hc = new HandlerCollection();
        ContextHandlerCollection contexts = new ContextHandlerCollection();
        for (Handler handler : handlers) {
            contexts.addHandler(handler);
        }
        hc.addHandler(contexts);

        if (props.JETTY_GZIP_ENABLED.get()) {
            HandlerWrapper gzipHandler = createGzipHandler();
            gzipHandler.setHandler(hc);
            statsHandler.setHandler(gzipHandler);
        } else {
            statsHandler.setHandler(hc);
        }

        jetty.setHandler(statsHandler);
        jetty.setStopAtShutdown(false);
        jetty.setStopTimeout(props.APP_PLATFORM_GRACEFUL_SHUTDOWN_TIMEOUT.get().toMillis());

        jetty.setConnectors(new Connector[] { connector });
        for (Connector next : jetty.getConnectors()) {
            next.addBean(stats);
        }

        jetty.start();
        String dump = jetty.dump();
        logger.debug(dump);
        logger.info("jetty server is up and running on {} port", port);
    }
    @SuppressWarnings("deprecation")
    protected void createConnector() {
        HttpConfiguration httpConfiguration = new HttpConfiguration();
        httpConfiguration.setSendServerVersion(props.isDevMode());
        httpConfiguration.setSendDateHeader(props.JETTY_HTTP_SEND_DATE_HEADER.get());
        httpConfiguration.setRequestHeaderSize(props.HTTP_HEADER_MAX_SIZE.get());
        httpConfiguration.addCustomizer(new org.eclipse.jetty.server.ForwardedRequestCustomizer());
        ConnectionFactory http = new HttpConnectionFactory(httpConfiguration);

        connector = new ServerConnector(jetty, http);
        connector.addBean(new JettyConnectionMetrics(meterRegistry));
        connector.addBean(new JettySslHandshakeMetrics(meterRegistry));
        connector.addBean(new io.micrometer.jetty11.TimedHandler(meterRegistry, Tags.empty()));
        connector.addBean(buildThreadPoolMetrics(jetty.getThreadPool(), meterRegistry));
        connector.setReuseAddress(true);
        connector.setPort(port);
    }
    protected JettyServerThreadPoolMetrics buildThreadPoolMetrics(ThreadPool threadPool, MeterRegistry registry) {
        JettyServerThreadPoolMetrics threadPoolMetrics = new JettyServerThreadPoolMetrics(threadPool, Tags.empty());
        threadPoolMetrics.bindTo(registry);
        return threadPoolMetrics;
    }
    protected GzipHandler createGzipHandler() {
        GzipHandler handler = new GzipHandler();
        logger.info("configured gzip handler with min-size={} ...", handler.getMinGzipSize());
        return handler;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy