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)");
}
}