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

com.tvd12.ezyhttp.server.tomcat.TomcatApplicationBootstrap Maven / Gradle / Ivy

The newest version!
package com.tvd12.ezyhttp.server.tomcat;

import static com.tvd12.ezyfox.util.EzyProcessor.processWithLogException;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ThreadFactory;

import javax.servlet.MultipartConfigElement;

import org.apache.catalina.Context;
import org.apache.catalina.Server;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.filters.CorsFilter;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;

import com.tvd12.ezyfox.annotation.EzyProperty;
import com.tvd12.ezyfox.util.EzyLoggable;
import com.tvd12.ezyfox.util.EzyStoppable;
import com.tvd12.ezyhttp.core.concurrent.HttpThreadFactory;
import com.tvd12.ezyhttp.core.util.FileSizes;
import com.tvd12.ezyhttp.server.core.ApplicationEntry;
import com.tvd12.ezyhttp.server.core.annotation.ApplicationBootstrap;

import lombok.AccessLevel;
import lombok.Setter;

@Setter
@ApplicationBootstrap
public class TomcatApplicationBootstrap
    extends EzyLoggable
    implements ApplicationEntry, EzyStoppable {

    @EzyProperty("server.port")
    protected int port = 8080;

    @EzyProperty("server.host")
    protected String host = "0.0.0.0";

    @EzyProperty("server.max_threads")
    protected int maxThreads = 256;

    @EzyProperty("server.min_threads")
    protected int minThreads = 16;

    @EzyProperty("server.idle_timeout")
    protected int idleTimeout = 150 * 1000;

    @EzyProperty("server.context.path")
    protected String contextPath;

    @EzyProperty("server.multipart.location")
    protected String multipartLocation =
        System.getProperty("java.io.tmpdir");

    @EzyProperty("server.multipart.file_size_threshold")
    protected String multipartFileSizeThreshold = "1MB";

    @EzyProperty("server.multipart.max_file_size")
    protected String multipartMaxFileSize = "5MB";

    @EzyProperty("server.multipart.max_request_size")
    protected String multipartMaxRequestSize = "5MB";

    @EzyProperty("server.compression.enable")
    protected boolean compressionEnable = true;

    @EzyProperty("server.compression.min_size")
    protected String compressionMinSize = "32B";

    @EzyProperty("cors.enable")
    protected boolean corsEnable;

    @EzyProperty("cors.allowed_origins")
    protected String allowedOrigins = "*";

    @EzyProperty("cors.allowed_headers")
    protected String allowedHeaders = "*";

    @EzyProperty("management.enable")
    protected boolean managementEnable = true;

    @EzyProperty("management.host")
    protected String managementHost = "0.0.0.0";

    @EzyProperty("management.port")
    protected int managementPort = 18080;

    @Setter(AccessLevel.NONE)
    protected Tomcat tomcat;

    @Setter(AccessLevel.NONE)
    protected Tomcat managementTomcat;

    protected final ThreadFactory startTomcatThreadFactory =
        HttpThreadFactory.create("start-tomcat");

    @Override
    public void start() throws Exception {
        tomcat = newTomcat(host, port, true);
        if (managementEnable) {
            managementTomcat = newTomcat(managementHost, managementPort, false);
        }
        startTomcat(tomcat);
        logger.info("http server started on: {}:{}", host, port);
        if (managementEnable) {
            startTomcat(managementTomcat);
            logger.info("management started on: {}:{}", managementHost, managementPort);
        }
    }

    protected Tomcat newTomcat(
        String host,
        int port,
        boolean normalServer
    ) throws Exception {
        final Tomcat answer = new Tomcat();
        answer.setHostname(host);
        answer.setPort(port);
        final String actualContextPath = new File(
            contextPath != null
                ? contextPath
                : System.getProperty("java.io.tmpdir")
        ).getAbsolutePath();
        final Context context = answer.addContext(
            "",
            actualContextPath
        );
        context.setSessionTimeout(idleTimeout);
        final Wrapper wrapper = answer.addServlet(
            "",
            "Servlet",
            new TomcatBlockingServlet()
        );
        wrapper.setAsyncSupported(true);
        final String actualMultipartLocation = multipartLocation != null
            ? multipartLocation
            : "tmp";
        final Path multipartPath = actualMultipartLocation.startsWith("/")
            ? Paths.get(actualMultipartLocation)
            : Paths.get(actualContextPath, actualMultipartLocation);
        if (!Files.exists(multipartPath)) {
            Files.createDirectories(multipartPath);
        }
        wrapper.setMultipartConfigElement(
            new MultipartConfigElement(
                multipartPath.toString(),
                FileSizes.toByteSize(multipartMaxFileSize),
                (int) FileSizes.toByteSize(multipartMaxRequestSize),
                (int) FileSizes.toByteSize(multipartFileSizeThreshold)
            )
        );
        context.addServletMappingDecoded("/*", "Servlet");
        if (corsEnable) {
            addCorsFilter(context);
        }
        final Connector connector = answer.getConnector();
        connector.setProperty(
            "minSpareThreads",
            String.valueOf(normalServer ? minThreads : 1)
        );
        connector.setProperty("maxThreads", String.valueOf(maxThreads));
        connector.setProperty("connectionTimeout", String.valueOf(idleTimeout));
        connector.setProperty("keepAliveTimeout", String.valueOf(idleTimeout));
        if (compressionEnable) {
            connector.setProperty("compression", "on");
            connector.setProperty(
                "compressionMinSize",
                String.valueOf(FileSizes.toByteSize(compressionMinSize))
            );
        }
        return answer;
    }

    protected void addCorsFilter(Context context) {
        final FilterDef filterDef = new FilterDef();
        filterDef.setFilterName("cross-origin");
        filterDef.setFilterClass(CorsFilter.class.getName());
        filterDef.addInitParameter(
            CorsFilter.PARAM_CORS_ALLOWED_ORIGINS,
            allowedOrigins
        );
        filterDef.addInitParameter(
            CorsFilter.PARAM_CORS_ALLOWED_HEADERS,
            allowedHeaders
        );
        context.addFilterDef(filterDef);

        final FilterMap filterMap = new FilterMap();
        filterMap.setFilterName("cross-origin");
        filterMap.addURLPattern("/*");
        context.addFilterMap(filterMap);
    }

    protected void startTomcat(Tomcat tomcatToStart) throws Exception {
        tomcatToStart.start();
        final Server server = tomcatToStart.getServer();
        startTomcatThreadFactory.newThread(server::await).start();
    }

    @Override
    public void stop() {
        if (tomcat != null) {
            processWithLogException(tomcat::destroy);
        }
        if (managementTomcat != null) {
            processWithLogException(managementTomcat::destroy);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy