io.github.factoryfx.jetty.JettyServerFactory Maven / Gradle / Ivy
package io.github.factoryfx.jetty;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.github.factoryfx.factory.FactoryBase;
import io.github.factoryfx.factory.attribute.dependency.FactoryAttribute;
import io.github.factoryfx.factory.attribute.dependency.FactoryListAttribute;
import io.github.factoryfx.factory.attribute.dependency.FactoryPolymorphicAttribute;
/**
* usage example.
*
* {@code
* public class SimpleHttpServer extends SimpleFactoryBase {
*
* public final FactoryAttribute> server = new FactoryAttribute<>(JettyServerFactory.class);
*
* {@literal @}Override
* protected Server createImpl() {
* return server.instance();
* }
* }
*
* builder.addFactory(JettyServerFactory.class, Scope.SINGLETON, ctx-> new JettyServerBuilder<>(new JettyServerFactory())
* .withHost("localhost").withPort(8005)
* .withResource(ctx.get(CustomResourceFactory.class)).build());
*
* }
*/
public class JettyServerFactory> extends FactoryBase {
private static final Logger jerseyLogger1 = Logger.getLogger(org.glassfish.jersey.internal.inject.Providers.class.getName());
private static final Logger jerseyLogger2 = Logger.getLogger(org.glassfish.jersey.internal.Errors.class.getName());
static {
jerseyLogger1.setLevel(Level.SEVERE); //another useless warning https://github.com/jersey/jersey/issues/3700
jerseyLogger2.setLevel(Level.SEVERE);//warning about generic parameters, works fine and no fix available so the warnings are just useless
}
public final FactoryListAttribute> connectors =
new FactoryListAttribute>().labelText("Connectors").userNotSelectable();
public final FactoryAttribute> handler =
new FactoryAttribute>().labelText("Handler collection");
public final FactoryPolymorphicAttribute threadPool =
new FactoryPolymorphicAttribute().labelText("Thread Pool").nullable();
public final FactoryPolymorphicAttribute requestLog =
new FactoryPolymorphicAttribute().labelText("RequestLog").nullable();
public JettyServerFactory() {
configLifeCycle().setCreator(this::createJetty);
configLifeCycle().setUpdater(this::update);
configLifeCycle().setStarter(this::start);
configLifeCycle().setDestroyer(this::stop);
config().setDisplayTextProvider(() -> "Jetty http server");
}
//api for customizing JettyServer creation
protected Server createJetty() {
Server server;
if (threadPool.get() == null) {
server = new Server();
} else {
server = new Server(threadPool.instance());
}
connectors.instances().forEach(httpServerConnector -> httpServerConnector.addToServer(server));
handler.instance().setServer(server);
server.setHandler(handler.instance());
server.setRequestLog(requestLog.instance());
return server;
}
@SuppressWarnings("unchecked")
private void update(Server server) {
for (Connector connector : server.getConnectors()) {
server.removeConnector(connector);
}
for (HttpServerConnector connector : connectors.instances()) {
connector.addToServer(server);
}
if (server.getThreadPool() instanceof QueuedThreadPool && threadPool.get() instanceof ThreadPoolFactory) {
((QueuedThreadPool) server.getThreadPool()).setMaxThreads(((ThreadPoolFactory) threadPool.get()).poolSize.get());
}
}
/**
* model navigation shortcut, only works with th e default setup form the builder
*
* @param clazz
* resource clazz
* @param
* resource factory
* @return resource
*/
public final > RF getResource(Class clazz) {
return getDefaultJerseyServlet().resources.get(clazz);
}
/**
* model navigation shortcut, only works with th e default setup form the builder
*
* @param resource
* resource
*/
public final void setResource(FactoryBase, R> resource) {
JerseyServletFactory jerseyServletFactory = getDefaultJerseyServlet();
jerseyServletFactory.resources.removeIf(factoryBase -> factoryBase.getClass() == resource.getClass());
jerseyServletFactory.resources.add(resource);
}
/**
* model navigation shortcut, only works with th e default setup form the builder
*
* @param clazz
* servlet class
* @param
* servlet factory
* @return servlet
*/
@SuppressWarnings("unchecked")
public final > F getServlet(Class clazz) {
ServletContextHandlerFactory servletContextHandler = getDefaultServletContextHandlerFactory();
for (ServletAndPathFactory servletAndPath : servletContextHandler.updatableRootServlet.get().servletAndPaths) {
if (servletAndPath.servlet.get().getClass() == clazz) {
return (F) servletAndPath.servlet.get();
}
}
return null;
}
@SuppressWarnings("unchecked")
public final > F getServletUnsafe(Class> clazz) {
return getServlet((Class) clazz);
}
public final > void clearResource(Class resource) {
getDefaultJerseyServlet().resources.removeIf(factoryBase -> factoryBase.getClass() == resource);
}
@SuppressWarnings("unchecked")
private JerseyServletFactory getDefaultJerseyServlet() {
ServletContextHandlerFactory servletContextHandler = getDefaultServletContextHandlerFactory();
ServletAndPathFactory servletAndPathFactory = servletContextHandler.updatableRootServlet.get().servletAndPaths.get(0);
return (JerseyServletFactory) servletAndPathFactory.servlet.get();
}
@SuppressWarnings("unchecked")
@JsonIgnore
public ServletContextHandlerFactory getDefaultServletContextHandlerFactory() {
return (ServletContextHandlerFactory) ((handler.get().handlers.get(GzipHandlerFactory.class)).handler.get());
}
public void start(Server server) throws Error {
try {
server.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void stop(Server server) {
try {
if (Thread.interrupted()) {throw new RuntimeException("Interrupted");}
//server.setStopTimeout(1L);
server.stop();
//because stop call can be inside this one of jetty's threads, we need to clear the interrupt
//to let the rest of the factory updates run. They might be interrupt-sensitive
Thread.interrupted();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy