public enum BundleContextHolder {

    INSTANCE;

    private BundleContext bundleContext;

    public BundleContext getBundleContext() {
        return this.bundleContext;
    }

    public void setBundleContext(BundleContext bundleContext) { // NOSONAR
        this.bundleContext = bundleContext;
    }

    public static BundleContextHolder getInstance() {
        return INSTANCE;
    }
} public final class Environment {

    /**
     * Deny direct instantiation.
     */
    private Environment() {
    }

    public static boolean isDev() {
        return ServerMode.DEV.toString().equalsIgnoreCase(System.getProperty(SYS_PROP_SERVER_MODE));
    }

    public static Path getServerConfPath() {
        return Paths.get(USER_DIR, DIR_ADEPTJ_RUNTIME, DIR_DEPLOYMENT, SERVER_CONF_FILE);
    }

    public static Path getFrameworkConfPath() {
        return Paths.get(USER_DIR, DIR_ADEPTJ_RUNTIME, DIR_DEPLOYMENT, FRAMEWORK_CONF_FILE);
    }
} public final class IOUtils {

    /**
     * Deny direct instantiation.
     */
    private IOUtils() {
    }

    public static String toString(InputStream input) throws IOException {
        return toByteArrayOutputStream(input).toString(UTF_8);
    }

    public static byte[] toBytes(InputStream input) throws IOException {
        return toByteArrayOutputStream(input).toByteArray();
    }

    private static ByteArrayOutputStream toByteArrayOutputStream(InputStream source) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        Streams.copyStream(source, out, false);
        return out;
    }
} public interface Lifecycle {

    void start(String[] args);

    void stop();
} public enum LogbackManagerHolder {

    INSTANCE;

    private LogbackManager logbackManager;

    public void setLogbackManager(LogbackManager logbackManager) {
        if (this.logbackManager == null) {
            this.logbackManager = logbackManager;
        }
    }

    public LogbackManager getLogbackManager() {
        return this.logbackManager;
    }

    public static LogbackManagerHolder getInstance() {
        return INSTANCE;
    }
} public final class SslContextFactory {

    private SslContextFactory() {
    }

    public static SSLContext newSslContext(Config httpsConf) throws GeneralSecurityException {
        String p12Loc;
        char[] p12Pwd;
        boolean p12FileExternal = Boolean.getBoolean(SYS_PROP_P12_FILE_EXTERNAL);
        if (p12FileExternal) {
            p12Loc = System.getProperty(SYS_PROP_P12_FILE_LOCATION);
            p12Pwd = System.getProperty(SYS_PROP_P12_PASSWORD).toCharArray();
        } else {
            p12Loc = httpsConf.getString(KEY_P12_FILE_LOCATION);
            p12Pwd = httpsConf.getString(KEY_P12_PASSWORD).toCharArray();
        }
        String keyStoreType = httpsConf.getString(KEY_KEYSTORE_TYPE);
        KeyStore keyStore = KeyStores.getKeyStore(p12FileExternal, keyStoreType, p12Loc, p12Pwd);
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, p12Pwd);
        String protocol = System.getProperty(SYS_PROP_TLS_VERSION, httpsConf.getString(KEY_TLS_VERSION));
        SSLContext sslContext = SSLContext.getInstance(protocol);
        // tm is initialized by SSLContext impl, that's why passing a null.
        sslContext.init(kmf.getKeyManagers(), null, null);
        return sslContext;
    }
} public final class Times {

    // No instances, just utility methods.
    private Times() {
    }

    /**
     * Returns elapsed time in milliseconds from the provided time in nanoseconds.
     *
     * @param startTime time in nanoseconds
     * @return elapsed time in milliseconds
     */
    public static long elapsedMillis(final long startTime) {
        return NANOSECONDS.toMillis(System.nanoTime() - startTime);
    }

    /**
     * Returns elapsed time in seconds from the provided time in milliseconds.
     *
     * @param startTime time in milliseconds
     * @return elapsed time in seconds
     */
    public static long elapsedSeconds(final long startTime) {
        return MILLISECONDS.toSeconds(System.currentTimeMillis() - startTime);
    }
} public enum Configs {

    INSTANCE;

    /**
     * This will include system properties as well.
     */
    private final Config root;

    Configs() {
        this.root = this.loadConf();
    }

    public Config root() {
        return this.root;
    }

    public Config main() {
        return this.root.getConfig(MAIN_CONF_SECTION);
    }

    public Config undertow() {
        return this.main().getConfig(UNDERTOW_CONF_SECTION);
    }

    public Config felix() {
        return this.main().getConfig(FELIX_CONF_SECTION);
    }

    public Config common() {
        return this.main().getConfig(COMMON_CONF_SECTION);
    }

    public Config logging() {
        return this.main().getConfig(LOGGING_CONF_SECTION);
    }

    public Config trimou() {
        return this.main().getConfig(TRIMOU_CONF_SECTION);
    }

    public Config resteasy() {
        return this.main().getConfig(RESTEASY_CONF_SECTION);
    }

    private Config loadConf() {
        Config config;
        File configFile = Environment.getServerConfPath().toFile();
        if (configFile.exists()) {
            // if overwrite.server.conf.file system property is provided, then load the configs from classpath.
            if (Boolean.getBoolean(SYS_PROP_OVERWRITE_SERVER_CONF)) {
                config = ConfigFactory.load(SERVER_CONF_FILE);
            } else {
                config = ConfigFactory.parseFile(configFile)
                        .withFallback(ConfigFactory.systemProperties())
                        .resolve();
            }
        } else {
            config = ConfigFactory.load(SERVER_CONF_FILE);
        }
        return config;
    }

    public static Configs of() {
        return INSTANCE;
    }

} @HandlesTypes(StartupAware.class)
public class RuntimeInitializer implements ServletContainerInitializer {

    private static final String SYS_PROP_SCAN_STARTUP_AWARE_CLASSES = "scan.startup.aware.classes";

    /**
     * {@inheritDoc}
     */
    @Override
    public void onStartup(Set<Class<?>> startupAwareClasses, ServletContext context) {
        ServletContextHolder.getInstance().setServletContext(context);
        Logger logger = LoggerFactory.getLogger(this.getClass());
        for (Class<?> startupAwareClass : startupAwareClasses) {
            logger.info("@HandlesTypes: [{}]", startupAwareClass);
            try {
                ((StartupAware) startupAwareClass.getConstructor().newInstance()).onStartup(context);
            } catch (Exception ex) { // NOSONAR
                logger.error("Exception while executing StartupAware#onStartup!!", ex);
                throw new RuntimeInitializationException(ex);
            }
        }
        context.addListener(FrameworkShutdownHandler.class);
        this.handleServiceLoaderBasedStartupAware(context, logger);
    }

    private void handleServiceLoaderBasedStartupAware(ServletContext context, Logger logger) {
        if (Boolean.getBoolean(SYS_PROP_SCAN_STARTUP_AWARE_CLASSES)) {
            for (StartupAware startupAware : ServiceLoader.load(StartupAware.class)) {
                logger.info("Found ServiceLoader based StartupAware: [{}]", startupAware);
                try {
                    startupAware.onStartup(context);
                } catch (Exception ex) { // NOSONAR
                    logger.error("Exception while executing ServiceLoader based StartupAware#onStartup!!", ex);
                }
            }
        }
    }
} public class RuntimeInitializationException extends RuntimeException {

    private static final long serialVersionUID = 6443421220206654015L;

    public RuntimeInitializationException(Throwable cause) {
        super(cause);
    }
} public class HealthCheckHandler implements HttpHandler {

    @Override
    public void handleRequest(HttpServerExchange exchange) {
        exchange.setStatusCode(OK);
        exchange.endExchange();
    }
} public final class ServletInitialHandlerWrapper implements HandlerWrapper {

    private static final String RESOURCE_PREFIX = "common.static-resource-prefix";

    private static final String RESOURCE_EXTNS = "common.static-resource-extns";

    private static final String RESOURCE_MGR_PREFIX = "common.resource-mgr-prefix";

    /**
     * Wraps the passed {@link ServletInitialHandler} with a PredicateHandler for serving static content.
     *
     * @param servletInitialHandler the ServletInitialHandler
     * @return PredicateHandler which decides whether to invoke ResourceHandler or pass on the request to
     * next handler in the chain which is ServletInitialHandler.
     * @see ServletInitialHandlerWrapper class header for detailed information.
     */
    @Override
    public HttpHandler wrap(HttpHandler servletInitialHandler) {
        Config cfg = Configs.of().undertow();
        Predicate prefix = Predicates.prefix(cfg.getString(RESOURCE_PREFIX));
        Predicate suffixes = Predicates.suffixes(cfg.getStringList(RESOURCE_EXTNS).toArray(new String[0]));
        ClassPathResourceManager rm = new ClassPathResourceManager(this.getClass().getClassLoader(),
                cfg.getString(RESOURCE_MGR_PREFIX));
        return Handlers.predicate(Predicates.and(prefix, suffixes), Handlers.resource(rm), servletInitialHandler);
    }
} public class FrameworkLauncher implements StartupAware {

    /**
     * This method will be called by the ServletContainerInitializer while startup is in progress.
     *
     * @param servletContext the {@link ServletContext}
     */
    @Override
    public void onStartup(ServletContext servletContext) {
        FrameworkManager.getInstance().startFramework();
    }
} public class ContextPathPredicate implements Predicate {

    private final String contextPath;

    public ContextPathPredicate(String contextPath) {
        this.contextPath = contextPath;
    }

    @Override
    public boolean resolve(HttpServerExchange value) {
        return value.getRequestPath().equals(this.contextPath);
    }
} @WebServlet(name = "AdeptJ AdminServlet", urlPatterns = ADMIN_SERVLET_URI, asyncSupported = true)
public class AdminServlet extends HttpServlet {

    private static final long serialVersionUID = -3339904764769823449L;

    private static final String LOGIN_TEMPLATE = "auth/login";

    private static final String J_USERNAME = "j_username";

    private static final String IS_LOGIN_ERROR = "isLoginError";

    /**
     * Render login page.
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        if (ADMIN_LOGIN_URI.equals(req.getRequestURI())) {
            TemplateEngine.getInstance().render(TemplateEngineContext.builder(LOGIN_TEMPLATE, resp).build());
            return;
        }
        if (ADMIN_LOGOUT_URI.equals(req.getRequestURI()) && req.isUserInRole(OSGI_ADMIN_ROLE)) {
            // Invalidate the session.
            RequestUtil.logout(req);
        }
        // if someone is requesting logout URI anonymously, redirect to /system/console/bundles.
        ResponseUtil.redirect(resp, Configs.of().undertow().getString(KEY_SYSTEM_CONSOLE_PATH));
    }

    /**
     * Handle "/admin/auth/j_security_check" validation failure, render the login page again with validation message.
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
        TemplateData templateData = new TemplateData(req.getLocale())
                .with(IS_LOGIN_ERROR, TRUE)
                .with(J_USERNAME, req.getParameter(J_USERNAME));
        TemplateEngineContext templateEngineContext = TemplateEngineContext.builder(LOGIN_TEMPLATE, resp)
                .templateData(templateData)
                .build();
        TemplateEngine.getInstance().render(templateEngineContext);
    }
} @WebServlet(name = "AdeptJ ErrorServlet", urlPatterns = ERROR_SERVLET_URI)
public class ErrorServlet extends HttpServlet {

    private static final long serialVersionUID = -3339904764769823449L;

    private static final String KEY_EXCEPTION = "exception";

    private static final String ERROR_TEMPLATE_FMT = "error/%s";

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) {
        // Make sure the below code is invoked only on an error dispatch.
        if (req.getDispatcherType() == ERROR) {
            String template = String.format(ERROR_TEMPLATE_FMT, resp.getStatus());
            TemplateEngineContext.Builder builder = TemplateEngineContext.builder(template, resp);
            if (Environment.isDev() && RequestUtil.hasException(req)) {
                builder.templateData(new TemplateData(req.getLocale()).with(KEY_EXCEPTION, RequestUtil.getException(req)));
            }
            TemplateEngine.getInstance().render(builder.build());
        }
    }
} public static final String ADMIN_LOGIN_URI = "/admin/login"; public static final String ATTRIBUTE_BUNDLE_CONTEXT = "org.osgi.framework.BundleContext"; public static final String BANNER_TXT = "/banner.txt"; public static final String DEPLOYMENT_NAME = "AdeptJ Runtime Deployment"; public static final String H2_MAP_ADMIN_CREDENTIALS = "adminCredentials"; public static final String KEY_ADMIN_SERVLET_PATH = "common.admin-servlet-path"; public static final String KEY_ALLOWED_METHODS = "common.server-allowed-methods"; public static final String KEY_ERROR_HANDLER_CODES = "common.error-handler-codes"; public static final String KEY_ERROR_HANDLER_PATH = "common.error-handler-path"; public static final String KEY_HEADER_SERVER = "common.header-server"; public static final String KEY_HOST = "host"; public static final String KEY_HTTP = "http"; public static final String KEY_LOGBACK_STATUS_SERVLET_PATH = "common.logback-status-servlet-path"; public static final String KEY_MAX_CONCURRENT_REQUESTS = "common.max-concurrent-requests"; public static final String KEY_PORT = "port"; public static final String KEY_REQ_BUFF_MAX_BUFFERS = "common.req-buffering-maxBuffers"; public static final String KEY_REQ_LIMIT_QUEUE_SIZE = "common.req-limit-queue-size"; public static final String KEY_SYSTEM_CONSOLE_PATH = "common.system-console-path"; public static final String MV_CREDENTIALS_STORE = "credentials.dat"; public static final String SERVER_CONF_CP_RESOURCE = "/server.conf"; public static final String SYS_PROP_OVERWRITE_SERVER_CONF = "overwrite.server.conf.file"; public static final String SYS_PROP_SERVER_PORT = "adeptj.rt.port"; static final String ADMIN_SERVLET_NAME = "AdeptJ AdminServlet"; static final long DEFAULT_WAIT_TIME = 30000L; static final String ERROR_SERVLET_NAME = "AdeptJ ErrorServlet"; static final String KEY_AUTH_ROLES = "common.auth-roles"; static final String KEY_CHANGE_SESSION_ID_ON_LOGIN = "common.change-sessionId-on-login"; static final String KEY_CONTEXT_PATH = "common.context-path"; static final String KEY_DEFAULT_ENCODING = "common.default-encoding"; static final String KEY_HEALTH_CHECK_HANDLER_PATH = "common.health-check-handler-path"; static final String KEY_HTTPS = "https"; static final String KEY_HTTP_ONLY = "common.session-cookie-httpOnly"; static final String KEY_IGNORE_FLUSH = "common.ignore-flush"; static final String KEY_INVALIDATE_SESSION_ON_LOGOUT = "common.invalidate-session-on-logout"; static final String KEY_MULTIPART_FILE_LOCATION = "common.multipart-file-location"; static final String KEY_MULTIPART_FILE_SIZE_THRESHOLD = "common.multipart-file-size-threshold"; static final String KEY_MULTIPART_MAX_FILE_SIZE = "common.multipart-max-file-size"; static final String KEY_MULTIPART_MAX_REQUEST_SIZE = "common.multipart-max-request-size"; static final String KEY_PROTECTED_PATHS = "common.protected-paths"; static final String KEY_PROTECTED_PATHS_SECURED_FOR_METHODS = "common.protected-paths-secured-for-methods"; static final String KEY_SESSION_TIMEOUT = "common.session-timeout"; static final String KEY_USER_CREDENTIAL_MAPPING = "common.user-credential-mapping"; static final String KEY_USE_CACHED_AUTH_MECHANISM = "common.use-cached-auth-mechanism"; static final String KEY_WORKER_OPTIONS = "worker-options"; static final String KEY_WORKER_TASK_CORE_THREADS = "WORKER_TASK_CORE_THREADS"; static final String KEY_WORKER_TASK_MAX_THREADS = "WORKER_TASK_MAX_THREADS"; static final String LOGBACK_STATUS_SERVLET_NAME = "Logback ViewStatusMessagesServlet"; static final int PWD_START_INDEX = 9; static final String REALM = "AdeptJ Realm"; static final String SYS_PROP_ENABLE_HTTP2 = "enable.http2"; static final String SYS_PROP_ENABLE_REQ_BUFF = "enable.req.buffering"; static final String SYS_PROP_MAX_CONCUR_REQ = "max.concurrent.requests"; static final String SYS_PROP_REQ_BUFF_MAX_BUFFERS = "req.buff.maxBuffers"; static final String SYS_PROP_REQ_LIMIT_QUEUE_SIZE = "req.limit.queue.size"; static final String SYS_PROP_SERVER_HTTPS_PORT = "adeptj.rt.https.port"; static final String SYS_PROP_SESSION_TIMEOUT = "adeptj.session.timeout"; static final String SYS_PROP_SHUTDOWN_WAIT_TIME = "shutdown.wait.time"; static final String SYS_PROP_SYS_TASK_THREAD_MULTIPLIER = "sys.task.thread.multiplier"; static final String SYS_PROP_WORKER_TASK_THREAD_MULTIPLIER = "worker.task.thread.multiplier"; static final int SYS_TASK_THREAD_MULTIPLIER = 2; static final int WORKER_TASK_THREAD_MULTIPLIER = 8;
import ch.qos.logback.classic.ViewStatusMessagesServlet;
import com.adeptj.runtime.common.BundleContextHolder;
import com.adeptj.runtime.common.Environment;
import com.adeptj.runtime.common.IOUtils;
import com.adeptj.runtime.common.Lifecycle;
import com.adeptj.runtime.common.LogbackManagerHolder;
import com.adeptj.runtime.common.SslContextFactory;
import com.adeptj.runtime.common.Times;
import com.adeptj.runtime.config.Configs;
import com.adeptj.runtime.core.RuntimeInitializer;
import com.adeptj.runtime.exception.RuntimeInitializationException;
import com.adeptj.runtime.handler.HealthCheckHandler;
import com.adeptj.runtime.handler.ServletInitialHandlerWrapper;
import com.adeptj.runtime.osgi.FrameworkLauncher;
import com.adeptj.runtime.predicate.ContextPathPredicate;
import com.adeptj.runtime.servlet.AdminServlet;
import com.adeptj.runtime.servlet.ErrorServlet;
import com.typesafe.config.Config;
import io.undertow.Handlers;
import io.undertow.Undertow;
import io.undertow.Undertow.Builder;
import io.undertow.server.HttpHandler;
import io.undertow.server.handlers.AllowedMethodsHandler;
import io.undertow.server.handlers.GracefulShutdownHandler;
import io.undertow.server.handlers.PathHandler;
import io.undertow.server.handlers.PredicateHandler;
import io.undertow.server.handlers.RedirectHandler;
import io.undertow.server.handlers.RequestBufferingHandler;
import io.undertow.server.handlers.RequestLimit;
import io.undertow.server.handlers.RequestLimitingHandler;
import io.undertow.server.handlers.SetHeaderHandler;
import io.undertow.servlet.Servlets;
import io.undertow.servlet.api.CrawlerSessionManagerConfig;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.DeploymentManager;
import io.undertow.servlet.api.ErrorPage;
import io.undertow.servlet.api.SecurityConstraint;
import io.undertow.servlet.api.ServletContainerInitializerInfo;
import io.undertow.servlet.api.ServletInfo;
import io.undertow.servlet.api.ServletSessionConfig;
import io.undertow.util.HttpString;
import org.apache.commons.lang3.StringUtils;
import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
import javax.net.ssl.SSLContext;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletContext;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.adeptj.runtime.common.Constants.ADMIN_LOGIN_URI;
import static com.adeptj.runtime.common.Constants.ATTRIBUTE_BUNDLE_CONTEXT;
import static com.adeptj.runtime.common.Constants.BANNER_TXT;
import static com.adeptj.runtime.common.Constants.DEPLOYMENT_NAME;
import static com.adeptj.runtime.common.Constants.H2_MAP_ADMIN_CREDENTIALS;
import static com.adeptj.runtime.common.Constants.KEY_ADMIN_SERVLET_PATH;
import static com.adeptj.runtime.common.Constants.KEY_ALLOWED_METHODS;
import static com.adeptj.runtime.common.Constants.KEY_ERROR_HANDLER_CODES;
import static com.adeptj.runtime.common.Constants.KEY_ERROR_HANDLER_PATH;
import static com.adeptj.runtime.common.Constants.KEY_HEADER_SERVER;
import static com.adeptj.runtime.common.Constants.KEY_HOST;
import static com.adeptj.runtime.common.Constants.KEY_HTTP;
import static com.adeptj.runtime.common.Constants.KEY_LOGBACK_STATUS_SERVLET_PATH;
import static com.adeptj.runtime.common.Constants.KEY_MAX_CONCURRENT_REQUESTS;
import static com.adeptj.runtime.common.Constants.KEY_PORT;
import static com.adeptj.runtime.common.Constants.KEY_REQ_BUFF_MAX_BUFFERS;
import static com.adeptj.runtime.common.Constants.KEY_REQ_LIMIT_QUEUE_SIZE;
import static com.adeptj.runtime.common.Constants.KEY_SYSTEM_CONSOLE_PATH;
import static com.adeptj.runtime.common.Constants.MV_CREDENTIALS_STORE;
import static com.adeptj.runtime.common.Constants.SERVER_CONF_CP_RESOURCE;
import static com.adeptj.runtime.common.Constants.SYS_PROP_OVERWRITE_SERVER_CONF;
import static com.adeptj.runtime.common.Constants.SYS_PROP_SERVER_PORT;
import static com.adeptj.runtime.server.ServerConstants.ADMIN_SERVLET_NAME;
import static com.adeptj.runtime.server.ServerConstants.DEFAULT_WAIT_TIME;
import static com.adeptj.runtime.server.ServerConstants.ERROR_SERVLET_NAME;
import static com.adeptj.runtime.server.ServerConstants.KEY_AUTH_ROLES;
import static com.adeptj.runtime.server.ServerConstants.KEY_CHANGE_SESSION_ID_ON_LOGIN;
import static com.adeptj.runtime.server.ServerConstants.KEY_CONTEXT_PATH;
import static com.adeptj.runtime.server.ServerConstants.KEY_DEFAULT_ENCODING;
import static com.adeptj.runtime.server.ServerConstants.KEY_HEALTH_CHECK_HANDLER_PATH;
import static com.adeptj.runtime.server.ServerConstants.KEY_HTTPS;
import static com.adeptj.runtime.server.ServerConstants.KEY_HTTP_ONLY;
import static com.adeptj.runtime.server.ServerConstants.KEY_IGNORE_FLUSH;
import static com.adeptj.runtime.server.ServerConstants.KEY_INVALIDATE_SESSION_ON_LOGOUT;
import static com.adeptj.runtime.server.ServerConstants.KEY_MULTIPART_FILE_LOCATION;
import static com.adeptj.runtime.server.ServerConstants.KEY_MULTIPART_FILE_SIZE_THRESHOLD;
import static com.adeptj.runtime.server.ServerConstants.KEY_MULTIPART_MAX_FILE_SIZE;
import static com.adeptj.runtime.server.ServerConstants.KEY_MULTIPART_MAX_REQUEST_SIZE;
import static com.adeptj.runtime.server.ServerConstants.KEY_PROTECTED_PATHS;
import static com.adeptj.runtime.server.ServerConstants.KEY_PROTECTED_PATHS_SECURED_FOR_METHODS;
import static com.adeptj.runtime.server.ServerConstants.KEY_SESSION_TIMEOUT;
import static com.adeptj.runtime.server.ServerConstants.KEY_USER_CREDENTIAL_MAPPING;
import static com.adeptj.runtime.server.ServerConstants.KEY_USE_CACHED_AUTH_MECHANISM;
import static com.adeptj.runtime.server.ServerConstants.KEY_WORKER_OPTIONS;
import static com.adeptj.runtime.server.ServerConstants.KEY_WORKER_TASK_CORE_THREADS;
import static com.adeptj.runtime.server.ServerConstants.KEY_WORKER_TASK_MAX_THREADS;
import static com.adeptj.runtime.server.ServerConstants.LOGBACK_STATUS_SERVLET_NAME;
import static com.adeptj.runtime.server.ServerConstants.PWD_START_INDEX;
import static com.adeptj.runtime.server.ServerConstants.REALM;
import static com.adeptj.runtime.server.ServerConstants.SYS_PROP_ENABLE_HTTP2;
import static com.adeptj.runtime.server.ServerConstants.SYS_PROP_ENABLE_REQ_BUFF;
import static com.adeptj.runtime.server.ServerConstants.SYS_PROP_MAX_CONCUR_REQ;
import static com.adeptj.runtime.server.ServerConstants.SYS_PROP_REQ_BUFF_MAX_BUFFERS;
import static com.adeptj.runtime.server.ServerConstants.SYS_PROP_REQ_LIMIT_QUEUE_SIZE;
import static com.adeptj.runtime.server.ServerConstants.SYS_PROP_SERVER_HTTPS_PORT;
import static com.adeptj.runtime.server.ServerConstants.SYS_PROP_SESSION_TIMEOUT;
import static com.adeptj.runtime.server.ServerConstants.SYS_PROP_SHUTDOWN_WAIT_TIME;
import static com.adeptj.runtime.server.ServerConstants.SYS_PROP_SYS_TASK_THREAD_MULTIPLIER;
import static com.adeptj.runtime.server.ServerConstants.SYS_PROP_WORKER_TASK_THREAD_MULTIPLIER;
import static com.adeptj.runtime.server.ServerConstants.SYS_TASK_THREAD_MULTIPLIER;
import static com.adeptj.runtime.server.ServerConstants.WORKER_TASK_THREAD_MULTIPLIER;
import static io.undertow.util.Headers.SERVER_STRING;
import static javax.servlet.http.HttpServletRequest.FORM_AUTH;
import static org.xnio.Options.WORKER_TASK_CORE_THREADS;
import static org.xnio.Options.WORKER_TASK_MAX_THREADS;
        }
    }

    private void setWorkerOptions(Builder builder, Config undertowConf) {
        long startTime = System.nanoTime();
        // Note : For a 16 core system, number of worker task core and max threads will be.
        // 1. core task thread: 128 (16[cores] * 8)
        // 2. max task thread: 128 * 2 = 256
        // Default settings would have set the following.
        // 1. core task thread: 128 (16[cores] * 8)
        // 2. max task thread: 128 (Same as core task thread)
        Config config = undertowConf.getConfig(KEY_WORKER_OPTIONS);
        // defaults to 64
        int cfgCoreTaskThreads = config.getInt(KEY_WORKER_TASK_CORE_THREADS);
        LOGGER.info("Configured worker task core threads: [{}]", cfgCoreTaskThreads);
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        LOGGER.info("No. of CPU available: [{}]", availableProcessors);
        int calcCoreTaskThreads = availableProcessors *
                Integer.getInteger(SYS_PROP_WORKER_TASK_THREAD_MULTIPLIER, WORKER_TASK_THREAD_MULTIPLIER);
        LOGGER.info("Calculated worker task core threads: [{}]", calcCoreTaskThreads);
        // defaults to double of [worker-task-core-threads] i.e 128
        int cfgMaxTaskThreads = config.getInt(KEY_WORKER_TASK_MAX_THREADS);
        LOGGER.info("Configured worker task max threads: [{}]", cfgMaxTaskThreads);
        int calcMaxTaskThreads = calcCoreTaskThreads *
                Integer.getInteger(SYS_PROP_SYS_TASK_THREAD_MULTIPLIER, SYS_TASK_THREAD_MULTIPLIER);
        LOGGER.info("Calculated worker task max threads: [{}]", calcMaxTaskThreads);
        WorkerOptions options = new WorkerOptions();
        options.setOptions(builder, undertowConf);
        options.overrideOption(builder, WORKER_TASK_CORE_THREADS, Math.max(cfgCoreTaskThreads, calcCoreTaskThreads))
                .overrideOption(builder, WORKER_TASK_MAX_THREADS, Math.max(cfgMaxTaskThreads, calcMaxTaskThreads));
        LOGGER.info("Undertow WorkerOptions configured in [{}] ms!!", Times.elapsedMillis(startTime));
    }

    private Builder addHttpsListener(Builder builder, Config undertowConf) throws GeneralSecurityException {
        if (Boolean.getBoolean(SYS_PROP_ENABLE_HTTP2)) {
            Config httpsConf = undertowConf.getConfig(KEY_HTTPS);
            int httpsPort = Integer.getInteger(SYS_PROP_SERVER_HTTPS_PORT, httpsConf.getInt(KEY_PORT));
            SSLContext sslContext = SslContextFactory.newSslContext(httpsConf);
            builder.addHttpsListener(httpsPort, httpsConf.getString(KEY_HOST), sslContext);
            LOGGER.info("HTTP2 enabled @ port: {}.", httpsPort);
        }
        return builder;
    }

    private int resolvePort(Config httpConf) {
        Integer port = Integer.getInteger(SYS_PROP_SERVER_PORT);
        if (port == null) {
            port = httpConf.getInt(KEY_PORT);
            LOGGER.info("No port specified via system property: [{}], using default port: [{}]", SYS_PROP_SERVER_PORT, port);
        }
        return port;
    }

    /**
     * Chaining of Undertow {@link HttpHandler} instances as follows.
     * <p>
     * 1. GracefulShutdownHandler
     * 2. RequestLimitingHandler
     * 3. AllowedMethodsHandler
     * 4. PathHandler which resolves to either PredicateHandler or HealthCheckHandler
     * 5. RequestBufferingHandler if request buffering is enabled, wrapped in SetHeadersHandler
     * 5. And Finally HttpContinueReadHandler
     *
     * @param httpContinueReadHandler the {@link io.undertow.server.handlers.HttpContinueReadHandler}
     * @param cfg                     the undertow server config object.
     * @return GracefulShutdownHandler as the root handler
     */
    private GracefulShutdownHandler createHandlerChain(HttpHandler httpContinueReadHandler, Config cfg) {
        RedirectHandler contextHandler = Handlers.redirect(cfg.getString(KEY_SYSTEM_CONSOLE_PATH));
        RequestBufferingHandler requestBufferingHandler = new RequestBufferingHandler(httpContinueReadHandler,
                Integer.getInteger(SYS_PROP_REQ_BUFF_MAX_BUFFERS, cfg.getInt(KEY_REQ_BUFF_MAX_BUFFERS)));
        HttpHandler headersHandler = Boolean.getBoolean(SYS_PROP_ENABLE_REQ_BUFF) ?
                new SetHeaderHandler(requestBufferingHandler, SERVER_STRING, cfg.getString(KEY_HEADER_SERVER)) :
                new SetHeaderHandler(httpContinueReadHandler, SERVER_STRING, cfg.getString(KEY_HEADER_SERVER));
        ContextPathPredicate contextPathPredicate = new ContextPathPredicate(cfg.getString(KEY_CONTEXT_PATH));
        PredicateHandler predicateHandler = Handlers.predicate(contextPathPredicate, contextHandler, headersHandler);
        PathHandler pathHandler = Handlers.path(predicateHandler)
                .addPrefixPath(cfg.getString(KEY_HEALTH_CHECK_HANDLER_PATH), new HealthCheckHandler());
        AllowedMethodsHandler allowedMethodsHandler = new AllowedMethodsHandler(pathHandler, this.allowedMethods(cfg));
        int maxConcurrentRequests = Integer.getInteger(SYS_PROP_MAX_CONCUR_REQ, cfg.getInt(KEY_MAX_CONCURRENT_REQUESTS));
        int queueSize = Integer.getInteger(SYS_PROP_REQ_LIMIT_QUEUE_SIZE, cfg.getInt(KEY_REQ_LIMIT_QUEUE_SIZE));
        RequestLimit limit = new RequestLimit(maxConcurrentRequests, queueSize);
        RequestLimitingHandler requestLimitingHandler = Handlers.requestLimitingHandler(limit, allowedMethodsHandler);
        return Handlers.gracefulShutdown(requestLimitingHandler);
    }

    private Set<HttpString> allowedMethods(Config cfg) {
        return cfg.getStringList(KEY_ALLOWED_METHODS)
                .stream()
                .map(HttpString::tryFromString)
                .collect(Collectors.toSet());
    }

    private List<ErrorPage> errorPages(Config undertowConf) {
        return undertowConf.getIntList(KEY_ERROR_HANDLER_CODES)
                .stream()
                .map(code -> Servlets.errorPage(undertowConf.getString(KEY_ERROR_HANDLER_PATH), code))
                .collect(Collectors.toList());
    }

    private ServletContainerInitializerInfo sciInfo() {
        // Since the execution order of StartupAware instances matter that's why a LinkedHashSet.
        // FrameworkLauncher must always be executed first.
        Set<Class<?>> handlesTypes = new LinkedHashSet<>();
        handlesTypes.add(FrameworkLauncher.class);
        handlesTypes.add(DefaultStartupAware.class);
        return new ServletContainerInitializerInfo(RuntimeInitializer.class, handlesTypes);
    }

    private SecurityConstraint securityConstraint(Config cfg) {
        return Servlets.securityConstraint()
                .addRolesAllowed(cfg.getStringList(KEY_AUTH_ROLES))
                .addWebResourceCollection(Servlets.webResourceCollection()
                        .addUrlPatterns(cfg.getStringList(KEY_PROTECTED_PATHS))
                        .addHttpMethods(cfg.getStringList(KEY_PROTECTED_PATHS_SECURED_FOR_METHODS)));
    }

    private List<ServletInfo> servlets(Config undertowConf) {
        List<ServletInfo> servlets = new ArrayList<>();
        servlets.add(Servlets
                .servlet(ERROR_SERVLET_NAME, ErrorServlet.class)