Skip to content

Commit

Permalink
Jetty 12 WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
rbygrave committed Nov 22, 2024
1 parent f381d91 commit fc153eb
Show file tree
Hide file tree
Showing 22 changed files with 1,654 additions and 509 deletions.
36 changes: 36 additions & 0 deletions avaje-j12/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.avaje</groupId>
<artifactId>avaje-jex-parent</artifactId>
<version>2.6-SNAPSHOT</version>
</parent>

<artifactId>avaje-j12</artifactId>

<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jetty.version>12.0.0</jetty.version>
<surefire.useModulePath>false</surefire.useModulePath>
</properties>

<dependencies>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-jex</artifactId>
<version>2.6-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
</dependencies>

</project>
59 changes: 59 additions & 0 deletions avaje-j12/src/main/java/io/avaje/jex/jetty/JettyBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.avaje.jex.jetty;

import io.avaje.jex.Jex;
import io.avaje.jex.JexConfig;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;

/**
* Build the Jetty Server.
*/
class JettyBuilder {

private static final Logger log = LoggerFactory.getLogger(JettyBuilder.class);

private final JexConfig jexConfig;
private final JettyServerConfig jettyConfig;

JettyBuilder(Jex jex, JettyServerConfig jettyConfig) {
this.jexConfig = jex.config();
this.jettyConfig = jettyConfig;
}

Server build() {
Server jetty = new Server(pool());
ServerConnector connector = new ServerConnector(jetty);
connector.setPort(jexConfig.port());
if (jexConfig.host() != null ) {
connector.setHost(jexConfig.host());
}
jetty.setConnectors(new Connector[]{connector});
return jetty;
}

private ThreadPool pool() {
if (jexConfig.virtualThreads()) {
return virtualThreadBasePool();
} else {
return jettyConfig.maxThreads() == 0 ? new QueuedThreadPool() : new QueuedThreadPool(jettyConfig.maxThreads());
}
}

private ThreadPool virtualThreadBasePool() {
try {
final Class<?> aClass = Class.forName("io.avaje.jex.jetty.threadpool.VirtualThreadPool");
final Constructor<?> constructor = aClass.getConstructor();
return (ThreadPool) constructor.newInstance();
} catch (Exception e) {
throw new IllegalStateException("Failed to start Loom threadPool", e);
}
}

}
168 changes: 168 additions & 0 deletions avaje-j12/src/main/java/io/avaje/jex/jetty/JettyJexServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package io.avaje.jex.jetty;

import io.avaje.jex.spi.SpiRoutes;
import io.avaje.jex.spi.SpiServiceManager;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.Uptime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

class JettyJexServer implements Jex.Server {

private static final Logger log = LoggerFactory.getLogger(Jex.class);

private final Jex jex;
private final SpiRoutes routes;
private final ServiceManager serviceManager;
private final JettyServerConfig config;
private final AppLifecycle lifecycle;
private final long startTime;
private final JexConfig jexConfig;
private Server server;

JettyJexServer(Jex jex, SpiRoutes routes, SpiServiceManager serviceManager) {
this.startTime = System.currentTimeMillis();
this.jex = jex;
this.jexConfig = jex.config();
this.lifecycle = jex.lifecycle();
this.routes = routes;
this.serviceManager = new ServiceManager(serviceManager);//, initMultiPart());
this.config = initConfig(jex.serverConfig());
}

private JettyServerConfig initConfig(ServerConfig config) {
return config == null ? new JettyServerConfig() : (JettyServerConfig) config;
}

// MultipartUtil initMultiPart() {
// return new MultipartUtil(initMultipartConfigElement(jexConfig.multipartConfig()));
// }
//
// MultipartConfigElement initMultipartConfigElement(UploadConfig uploadConfig) {
// if (uploadConfig == null) {
// final int fileThreshold = jexConfig.multipartFileThreshold();
// return new MultipartConfigElement(System.getProperty("java.io.tmpdir"), -1, -1, fileThreshold);
// }
// return new MultipartConfigElement(uploadConfig.location(), uploadConfig.maxFileSize(), uploadConfig.maxRequestSize(), uploadConfig.fileSizeThreshold());
// }

@Override
public void onShutdown(Runnable onShutdown) {
lifecycle.onShutdown(onShutdown, Integer.MAX_VALUE);
}

@Override
public void restart() {
try {
server.start();
logOnStart(server);
lifecycle.status(AppLifecycle.Status.STARTED);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@Override
public void shutdown() {
try {
log.trace("starting shutdown");
lifecycle.status(AppLifecycle.Status.STOPPING);
routes.waitForIdle(30);
server.stop();
log.trace("server http listeners stopped");
lifecycle.status(AppLifecycle.Status.STOPPED);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@Override
public int port() {
return server.getURI().getPort();
}

protected Jex.Server start() {
try {
createServer();
server.start();
logOnStart(server);
lifecycle.registerShutdownHook(this::shutdown);
lifecycle.status(AppLifecycle.Status.STARTED);
return this;
} catch (Exception e) {
throw new IllegalStateException("Error starting server", e);
}
}

protected void createServer() {
server = initServer();
//server.setErrorHandler();
server.setHandler(initJettyHandler());
if (server.getStopAtShutdown()) {
// do not use Jetty ShutdownHook, use the AppLifecycle one instead
server.setStopAtShutdown(false);
}
config.server(server);
config.postConfigure();
}

protected Server initServer() {
Server server = config.server();
if (server != null) {
return server;
}
return new JettyBuilder(jex, config).build();
}

protected Handler initJettyHandler() {
var baseHandler = new JexHandler(jex, routes, serviceManager, initStaticHandler());
return baseHandler;
// if (!config.sessions()) {
// return baseHandler;
// }
// var sessionHandler = initSessionHandler();
// sessionHandler.setHandler(baseHandler);
// return sessionHandler;
}

// protected SessionHandler initSessionHandler() {
// SessionHandler sh = config.sessionHandler();
// return sh == null ? defaultSessionHandler() : sh;
// }
//
// protected SessionHandler defaultSessionHandler() {
// SessionHandler sh = new SessionHandler();
// sh.setHttpOnly(true);
// return sh;
// }

protected StaticHandler initStaticHandler() {
final List<StaticFileSource> fileSources = jex.staticFiles().getSources();
if (fileSources == null || fileSources.isEmpty()) {
return null;
}
StaticHandlerFactory factory = new StaticHandlerFactory();
return factory.build(server, jex, fileSources);
}

private void logOnStart(org.eclipse.jetty.server.Server server) {
long startup = System.currentTimeMillis() - startTime;
for (Connector c : server.getConnectors()) {
String virtualThreads = jexConfig.virtualThreads() ? "with virtualThreads" : "";
if (c instanceof ServerConnector) {
ServerConnector sc = (ServerConnector) c;
String host = (sc.getHost() == null) ? "0.0.0.0" : sc.getHost();
log.info("Listening with {} {}:{} in {}ms @{}ms {}", sc.getProtocols(), host, sc.getLocalPort(), startup, Uptime.getUptime(), virtualThreads);
} else {
log.info("bind to {} in {}ms @{}ms {}", c, startup, Uptime.getUptime(), virtualThreads);
}
}
}


}
108 changes: 108 additions & 0 deletions avaje-j12/src/main/java/io/avaje/jex/jetty/JettyServerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package io.avaje.jex.jetty;

import io.avaje.jex.ServerConfig;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class JettyServerConfig implements ServerConfig {

private boolean sessions = true;
private boolean security = true;

/**
* Set maxThreads when using default QueuedThreadPool. Defaults to 200.
*/
private int maxThreads;
// private SessionHandler sessionHandler;
private Handler contextHandler;
private Server server;
private final List<Consumer<JettyServerConfig>> configureCallback = new ArrayList<>();

public boolean sessions() {
return sessions;
}

public JettyServerConfig sessions(boolean sessions) {
this.sessions = sessions;
return this;
}

public boolean security() {
return security;
}

public JettyServerConfig security(boolean security) {
this.security = security;
return this;
}

public int maxThreads() {
return maxThreads;
}

public JettyServerConfig maxThreads(int maxThreads) {
this.maxThreads = maxThreads;
return this;
}

// public SessionHandler sessionHandler() {
// return sessionHandler;
// }
//
// /**
// * Set the SessionHandler to use. When not set one is created automatically.
// */
// public JettyServerConfig sessionHandler(SessionHandler sessionHandler) {
// this.sessionHandler = sessionHandler;
// return this;
// }

public Handler contextHandler() {
return contextHandler;
}

/**
* Set the Jetty Handler to use. When not set one is created automatically.
*/
public JettyServerConfig contextHandler(Handler contextHandler) {
this.contextHandler = contextHandler;
return this;
}

public Server server() {
return server;
}

/**
* Set the Jetty Server to use. When not set one is created automatically.
*/
public JettyServerConfig server(Server server) {
this.server = server;
return this;
}

/**
* Register a callback that is executed after the server and contextHandler have been
* created but before the server has started.
* <p>
* When we use this to register filters to the ServletContextHandler or perform other
* changes prior to the server starting.
*/
public JettyServerConfig register(Consumer<JettyServerConfig> callback) {
configureCallback.add(callback);
return this;
}

/**
* Run configuration callbacks prior to starting the server.
*/
void postConfigure() {
for (Consumer<JettyServerConfig> callback : configureCallback) {
callback.accept(this);
}
}
}
17 changes: 17 additions & 0 deletions avaje-j12/src/main/java/io/avaje/jex/jetty/JettyStartServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.avaje.jex.jetty;

import io.avaje.jex.Jex;
import io.avaje.jex.spi.SpiRoutes;
import io.avaje.jex.spi.SpiServiceManager;
import io.avaje.jex.spi.SpiStartServer;

/**
* Configure and starts the underlying Jetty server.
*/
public class JettyStartServer implements SpiStartServer {

@Override
public Jex.Server start(Jex jex, SpiRoutes routes, SpiServiceManager serviceManager) {
return new JettyJexServer(jex, routes, serviceManager).start();
}
}
Loading

0 comments on commit fc153eb

Please sign in to comment.