private void initializeJetty()

in http/jetty12/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java [274:463]


    private void initializeJetty() throws Exception
    {
        if (this.config.isUseHttp() || this.config.isUseHttps())
        {

            final int threadPoolMax = this.config.getThreadPoolMax();
            if (!this.config.isUseVirtualThreads() && threadPoolMax >= 0) {
                this.server = new Server(new QueuedThreadPool(threadPoolMax));
            } else if (this.config.isUseVirtualThreads()){
                // See https://jetty.org/docs/jetty/12/programming-guide/arch/threads.html#thread-pool-virtual-threads
                Method newVirtualThreadPerTaskExecutorMethod = null;
                try {
                    newVirtualThreadPerTaskExecutorMethod = Executors.class.getMethod("newVirtualThreadPerTaskExecutor");
                } catch (NoSuchMethodException e){
                    throw new IllegalArgumentException("Virtual threads are only available in Java 21 or later, or via preview flags in Java 19-20");
                }
                if (threadPoolMax >= 0) {
                    // Configurable, bounded, virtual thread executor
                    VirtualThreadPool threadPool = new VirtualThreadPool();
                    threadPool.setMaxThreads(threadPoolMax);
                    this.server = new Server(threadPool);
                } else {
                    // Simple, unlimited, virtual thread Executor
                    QueuedThreadPool threadPool = new QueuedThreadPool();
                    final Executor virtualExecutor = (Executor) newVirtualThreadPerTaskExecutorMethod.invoke(null);
                    threadPool.setVirtualThreadsExecutor(virtualExecutor);
                    this.server = new Server(threadPool);
                }
            } else {
                this.server = new Server();
            }

            // FELIX-5931 : PropertyUserStore used as default by HashLoginService has changed in 9.4.12.v20180830
            //              and fails without a config, therefore using plain UserStore
            final HashLoginService loginService = new HashLoginService("OSGi HTTP Service Realm");
            loginService.setUserStore(new UserStore());
            this.server.addBean(loginService);

            ServletContextHandler context = new ServletContextHandler(this.config.getContextPath(),                    
                    ServletContextHandler.SESSIONS);

            this.parent = new ContextHandlerCollection(context);

            configureSessionManager(context);
            this.controller.getEventDispatcher().setActive(true);
            context.addEventListener(controller.getEventDispatcher());
            context.getSessionHandler().addEventListener(controller.getEventDispatcher());

            final ServletHolder holder = new ServletHolder(this.controller.createDispatcherServlet());
            holder.setAsyncSupported(true);
            context.addServlet(holder, "/*");
            context.setMaxFormContentSize(this.config.getMaxFormSize());

            if (this.config.isRegisterMBeans())
            {
                this.mbeanServerTracker = new MBeanServerTracker(this.context, this.server);
                this.mbeanServerTracker.open();
                if (!this.config.isStatisticsHandlerEnabled()) {
                  context.addBean(new StatisticsHandler());
                }
            }

            this.server.setHandler(this.parent);

            if (this.config.isStatisticsHandlerEnabled()) {
              StatisticsHandler statisticsHandler = new StatisticsHandler();
              this.server.insertHandler(statisticsHandler);
              if (this.config.isRegisterMBeans())
              {
                context.addBean(statisticsHandler);
              }
            }

            if (this.config.isGzipHandlerEnabled())
            {
            	GzipHandler gzipHandler = new GzipHandler();
            	gzipHandler.setMinGzipSize(this.config.getGzipMinGzipSize());
            	gzipHandler.setInflateBufferSize(this.config.getGzipInflateBufferSize());
            	gzipHandler.setSyncFlush(this.config.isGzipSyncFlush());
            	gzipHandler.addIncludedMethods(this.config.getGzipIncludedMethods());
            	gzipHandler.addExcludedMethods(this.config.getGzipExcludedMethods());
            	gzipHandler.addIncludedPaths(this.config.getGzipIncludedPaths());
            	gzipHandler.addExcludedPaths(this.config.getGzipExcludedPaths());
            	gzipHandler.addIncludedMimeTypes(this.config.getGzipIncludedMimeTypes());
            	gzipHandler.addExcludedMimeTypes(this.config.getGzipExcludedMimeTypes());

            	this.server.insertHandler(gzipHandler);
            }

            if(this.config.getStopTimeout() != -1)
            {
                this.server.setStopTimeout(this.config.getStopTimeout());
            }

            if (this.config.isUseJettyWebsocket()) {
                maybeInitializeJettyWebsocket(context);
            }

            if (this.config.isUseJakartaWebsocket()) {
                maybeInitializeJakartaWebsocket(context);
            }

            this.server.start();

            maybeStoreWebSocketContainerAttributes(context);

            // session id manager is only available after server is started
            context.getSessionHandler().getSessionIdManager().getSessionHouseKeeper().setIntervalSec(
                    this.config.getLongProperty(JettyConfig.FELIX_JETTY_SESSION_SCAVENGING_INTERVAL,
                            HouseKeeper.DEFAULT_PERIOD_MS / 1000L));

            if (this.config.isProxyLoadBalancerConnection())
            {
                customizerWrapper = new CustomizerWrapper();
                this.loadBalancerCustomizerTracker = new LoadBalancerCustomizerFactoryTracker(this.context, customizerWrapper);
                this.loadBalancerCustomizerTracker.open();
            }

            final StringBuilder message = new StringBuilder("Started Jetty ").append(this.jettyVersion).append(" at port(s)");
            if (this.config.isUseHttp() && initializeHttp())
            {
                message.append(" HTTP:").append(this.config.getHttpPort());
            }

            if (this.config.isUseHttps() && initializeHttps())
            {
                message.append(" HTTPS:").append(this.config.getHttpsPort());
            }

            this.connectorTracker = new ConnectorFactoryTracker(this.context, this.server);
            this.connectorTracker.open();

            if (this.server.getConnectors() != null && this.server.getConnectors().length > 0)
            {
                message.append(" on context path ").append(this.config.getContextPath());

                message.append(" [");
                ThreadPool threadPool = this.server.getThreadPool();
                if (threadPool instanceof ThreadPool.SizedThreadPool) {
                    ThreadPool.SizedThreadPool sizedThreadPool = (ThreadPool.SizedThreadPool) threadPool;
                    message.append("minThreads=").append(sizedThreadPool.getMinThreads()).append(",");
                    message.append("maxThreads=").append(sizedThreadPool.getMaxThreads()).append(",");
                } else if (threadPool instanceof VirtualThreadPool) {
                    VirtualThreadPool sizedThreadPool = (VirtualThreadPool) threadPool;
                    message.append("maxVirtualThreads=").append(sizedThreadPool.getMaxThreads()).append(",");
                }
                Connector connector = this.server.getConnectors()[0];
                if (connector instanceof ServerConnector) {
                    @SuppressWarnings("resource")
                    ServerConnector serverConnector = (ServerConnector) connector;
                    message.append("acceptors=").append(serverConnector.getAcceptors()).append(",");
                    message.append("selectors=").append(serverConnector.getSelectorManager().getSelectorCount());
                }
                message.append(",").append("virtualThreadsEnabled=").append(this.config.isUseVirtualThreads());
                message.append("]");

                SystemLogger.LOGGER.info(message.toString());
                this.controller.register(context.getServletContext(), getServiceProperties());
            }
            else
            {
                this.stopJetty();
                SystemLogger.LOGGER.error("Jetty stopped (no connectors available)");
            }

            try {
                this.requestLogTracker = new RequestLogTracker(this.context, this.config.getRequestLogFilter());
                this.requestLogTracker.open();
                this.server.setRequestLog(requestLogTracker);
            } catch (InvalidSyntaxException e) {
                SystemLogger.LOGGER.error("Invalid filter syntax in request log tracker", e);
            }

            if (this.config.isRequestLogOSGiEnabled()) {
                this.osgiRequestLog = new LogServiceRequestLog(this.config);
                this.osgiRequestLog.register(this.context);
                SystemLogger.LOGGER.info("Directing Jetty request logs to the OSGi Log Service");
            }

            if (this.config.getRequestLogFilePath() != null && !this.config.getRequestLogFilePath().isEmpty()) {
                this.fileRequestLog = new FileRequestLog(config);
                this.fileRequestLog.start(this.context);
                SystemLogger.LOGGER.info("Directing Jetty request logs to {}", this.config.getRequestLogFilePath());
            }
        }
        else
        {
            SystemLogger.LOGGER.warn("Jetty not started (HTTP and HTTPS disabled)");
        }
    }