io.github.factoryfx.jetty.builder.JettyServerBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jettyFactory Show documentation
Show all versions of jettyFactory Show documentation
factoryfx dependency injection framework
package io.github.factoryfx.jetty.builder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.glassfish.jersey.logging.LoggingFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.factoryfx.factory.FactoryBase;
import io.github.factoryfx.factory.builder.FactoryContext;
import io.github.factoryfx.factory.builder.FactoryTemplateId;
import io.github.factoryfx.factory.builder.FactoryTreeBuilder;
import io.github.factoryfx.factory.builder.NestedBuilder;
import io.github.factoryfx.factory.builder.Scope;
import io.github.factoryfx.jetty.GzipHandlerFactory;
import io.github.factoryfx.jetty.HandlerCollectionFactory;
import io.github.factoryfx.jetty.HttpConfigurationFactory;
import io.github.factoryfx.jetty.HttpServerConnectorFactory;
import io.github.factoryfx.jetty.JettyServerFactory;
import io.github.factoryfx.jetty.ServletAndPathFactory;
import io.github.factoryfx.jetty.ServletContextHandlerFactory;
import io.github.factoryfx.jetty.ServletFilterAndPathFactory;
import io.github.factoryfx.jetty.Slf4jRequestLogFactory;
import io.github.factoryfx.jetty.ThreadPoolFactory;
import io.github.factoryfx.jetty.UpdateableServletFactory;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter;
import jakarta.servlet.Servlet;
import jakarta.ws.rs.ext.ExceptionMapper;
/**
* The builder builds the factory structure for a jetty server not the jetty liveobject
* The factory structure matches the jetty internal architecture and the JettyServerBuilder creates a default configuration for that.
*
* {@code jetty builder==>jetty factories=>real jetty server}
*
* @see https://dzone.com/refcardz/jetty?chapter=2
* @param server root
*/
public class JettyServerBuilder, JR extends JettyServerFactory> implements NestedBuilder {
private final List> additionalServletBuilders = new ArrayList<>();
private final List> servletFilterBuilders = new ArrayList<>();
private FactoryBase firstHandler;
private int threadPoolSize=200;
private boolean enabledRequestLog=true;
private final FactoryTemplateId rootTemplateId;
private ServerConnectorBuilder defaultServerConnector;
private List> serverConnectorBuilders =new ArrayList<>();
private ResourceBuilder resourceBuilder;
private List> resourceBuilders =new ArrayList<>();
private Consumer additionalConfiguration = jr-> {};
private final FactoryTemplateId> threadPoolFactoryTemplateId;
private final FactoryTemplateId> requestLogerTemplateId;
private final FactoryTemplateId> handlerCollectionFactoryTemplateId;
private final FactoryTemplateId> gzipHandlerFactoryTemplateId;
private final FactoryTemplateId> servletContextHandlerFactoryTemplateId;
private final FactoryTemplateId> updateableServletFactoryTemplateId;
private final FactoryTemplateId> defaultServerConnectorTemplateId;
private Consumer> gzipHandlerCustomizer=(gzipHandler)->{};
private final Supplier jettyRootCreator;
public JettyServerBuilder(FactoryTemplateId rootTemplateId, Supplier jettyRootCreator){
this.rootTemplateId=rootTemplateId;
this.jettyRootCreator=jettyRootCreator;
this.threadPoolFactoryTemplateId=new FactoryTemplateId<>(rootTemplateId.name, ThreadPoolFactory.class);
this.requestLogerTemplateId=new FactoryTemplateId<>(rootTemplateId.name, Slf4jRequestLogFactory.class);
this.handlerCollectionFactoryTemplateId=new FactoryTemplateId<>(rootTemplateId.name, HandlerCollectionFactory.class);
this.gzipHandlerFactoryTemplateId=new FactoryTemplateId<>(rootTemplateId.name, GzipHandlerFactory.class);
this.servletContextHandlerFactoryTemplateId=new FactoryTemplateId<>(rootTemplateId.name, ServletContextHandlerFactory.class);
this.updateableServletFactoryTemplateId=new FactoryTemplateId<>(rootTemplateId.name, UpdateableServletFactory.class);
this.defaultServerConnectorTemplateId=new FactoryTemplateId<>(rootTemplateId.name, HttpServerConnectorFactory.class);
}
/**
* add a jetty connector, useful for jetty on multiple ports or support both http and ssl
*
* @param connectorBuilderSetup connectorBuilderSetup e.g. {@code withAdditionalConnector((connector)->connector.withPort(8080),"con1")}
* @param name builder unique name, used in the builder to associate match the templates
* @return builder
*/
public JettyServerBuilder withAdditionalConnector(Consumer> connectorBuilderSetup, FactoryTemplateName name){
ServerConnectorBuilder resourceBuilder = new ServerConnectorBuilder<>(new FactoryTemplateId<>(this.rootTemplateId.name+name.name, ServletAndPathFactory.class));
connectorBuilderSetup.accept(resourceBuilder);
serverConnectorBuilders.add(resourceBuilder);
return this;
}
/**
* add a jetty connector, useful for jetty on multiple ports or support both http and ssl
*
* @param connectorBuilderSetup connectorBuilderSetup e.g. {@code withAdditionalConnector((connector)->connector.withPort(8080),"con1")}
* @param name builder unique name, used in the builder to associate match the templates
* @return builder
*/
public JettyServerBuilder setAdditionalConnector(Consumer> connectorBuilderSetup, FactoryTemplateName name){
serverConnectorBuilders.clear();
ServerConnectorBuilder resourceBuilder = new ServerConnectorBuilder<>(new FactoryTemplateId<>(this.rootTemplateId.name+name.name, ServletAndPathFactory.class));
connectorBuilderSetup.accept(resourceBuilder);
serverConnectorBuilders.add(resourceBuilder);
return this;
}
/**
* add a new jersey servlet with REST Resources
* this can be used to support different ObjectMappers/ExceptionHandler
*
* @param resourceBuilderSetup resourceBuilderSetup
* @param name builder unique name, used in the builder to associate match the templates
* @return builder
*/
public JettyServerBuilder withJersey(Consumer> resourceBuilderSetup, FactoryTemplateName name){
ResourceBuilder resourceBuilder = new ResourceBuilder<>(new FactoryTemplateId<>(this.rootTemplateId.name+name.name, ServletAndPathFactory.class));
resourceBuilderSetup.accept(resourceBuilder);
addResourceBuilder(resourceBuilder);
return this;
}
/**
* adds a servlet
* @param servlet servlet
* @param pathSpec pathSpec
* @param name builder unique name, used in the builder to associate match the templates
* @return builder
*/
public JettyServerBuilder withServlet(FactoryBase extends Servlet, R> servlet, String pathSpec, FactoryTemplateName name){
additionalServletBuilders.add(new ServletBuilder<>(new FactoryTemplateId<>(null,name.name),pathSpec,servlet));
return this;
}
/**
* adds a servlet
* @param templateId templateId for the servlet
* @param pathSpec pathSpec
* @param servlet servlet
* @return builder
*/
public JettyServerBuilder withServlet(FactoryTemplateId> templateId, String pathSpec, FactoryBase extends Servlet, R> servlet){
additionalServletBuilders.add(new ServletBuilder<>(templateId,pathSpec,servlet));
return this;
}
/**
* adds a servlet filter
* @param filter filter
* @param pathSpec pathSpec
* @param name builder unique name, used in the builder to associate match the templates
* @return builder
*/
public JettyServerBuilder withServletFilter(FactoryBase extends Filter, R> filter, String pathSpec, FactoryTemplateName name){
servletFilterBuilders.add(new ServletFilterBuilder<>(new FactoryTemplateId<>(null,name.name),pathSpec,filter));
return this;
}
/**
* adds a servlet filter
* @param templateId templateId for the filter
* @param pathSpec pathSpec
* @param filter filter
* @return builder
*/
public JettyServerBuilder withServletFilter(FactoryTemplateId> templateId, String pathSpec, FactoryBase extends Filter, R> filter){
servletFilterBuilders.add(new ServletFilterBuilder<>(templateId,pathSpec,filter));
return this;
}
/**
* default is 200
* @param size jetty thread pool size
* @return builder
*/
public JettyServerBuilder withThreadPoolSize(int size){
this.threadPoolSize=size;
return this;
}
/**
* disable the jetty request log
* @return builder
*/
public JettyServerBuilder withDisabledRequestLog(){
this.enabledRequestLog=false;
return this;
}
/**
* adds a handler ad the first HandlerCollection position (with means handler is executed before the default)
* @param firstHandler creator
* @return builder
*/
public JettyServerBuilder withHandlerFirst(FactoryBase firstHandler) {
this.firstHandler=firstHandler;
return this;
}
/**
* customize the gzipHandler setup
* @param gzipHandlerCustomizer customizer consumer
* @return builder
*/
public JettyServerBuilder withGzipHandlerCustomizer(Consumer> gzipHandlerCustomizer) {
this.gzipHandlerCustomizer = gzipHandlerCustomizer;
return this;
}
/**
* customize the jetty server
* @param config customizer consumer
* @return builder
*/
public JettyServerBuilder withSpecificConfiguration(Consumer config) {
this.additionalConfiguration = config;
return this;
}
private > void addFactory(FactoryTreeBuilder,R> builder, FactoryTemplateId templateId, Scope scope, Function, F> creator){
builder.removeFactory(templateId);
builder.addFactory(templateId,scope,creator);
}
/**
* internal method
* @param builder tree builder to add
*/
@Override
public void internal_build(FactoryTreeBuilder,R> builder){
addFactory(builder,rootTemplateId, Scope.SINGLETON, (FactoryContext ctx) ->{
JR jettyServerFactory=jettyRootCreator.get();
additionalConfiguration.accept(jettyServerFactory);
jettyServerFactory.threadPool.set(ctx.get(threadPoolFactoryTemplateId));
if (enabledRequestLog) {
jettyServerFactory.requestLog.set(ctx.get(requestLogerTemplateId));
}
for (ServerConnectorBuilder connectorBuilder : serverConnectorBuilders) {
jettyServerFactory.connectors.add( ctx.get(connectorBuilder.getTemplateId()));
}
jettyServerFactory.handler.set(ctx.get(handlerCollectionFactoryTemplateId));
return jettyServerFactory;
});
if (enabledRequestLog) {
addFactory(builder,requestLogerTemplateId, Scope.SINGLETON, (ctx) -> {
return new Slf4jRequestLogFactory<>();
});
}
addFactory(builder,threadPoolFactoryTemplateId, Scope.SINGLETON, (ctx)->{
ThreadPoolFactory threadPoolFactory=new ThreadPoolFactory<>();
threadPoolFactory.poolSize.set(threadPoolSize);
return threadPoolFactory;
});
for (ServerConnectorBuilder connectorBuilder : serverConnectorBuilders) {
connectorBuilder.build(builder);
}
addFactory(builder,handlerCollectionFactoryTemplateId, Scope.SINGLETON, (ctx)->{
HandlerCollectionFactory handlerCollection = new HandlerCollectionFactory<>();
if (firstHandler!=null) {
handlerCollection.handlers.add(firstHandler);
}
handlerCollection.handlers.add(ctx.get(gzipHandlerFactoryTemplateId));
return handlerCollection;
});
addFactory(builder,gzipHandlerFactoryTemplateId, Scope.SINGLETON, (ctx)->{
GzipHandlerFactory gzipHandler = new GzipHandlerFactory<>();
gzipHandler.minGzipSize.set(23);
gzipHandler.dispatcherTypes.add(DispatcherType.REQUEST);
gzipHandler.inflateBufferSize.set(-1);
gzipHandler.syncFlush.set(false);
gzipHandler.handler.set(ctx.get(servletContextHandlerFactoryTemplateId));
gzipHandlerCustomizer.accept(gzipHandler);
return gzipHandler;
});
addFactory(builder,servletContextHandlerFactoryTemplateId, Scope.SINGLETON, (ctx)->{
ServletContextHandlerFactory servletContextHandlerFactory = new ServletContextHandlerFactory<>();
servletContextHandlerFactory.updatableRootServlet.set(ctx.get(updateableServletFactoryTemplateId));
for (ServletFilterBuilder servletFilterBuilder : servletFilterBuilders) {
servletContextHandlerFactory.servletFilters.add(ctx.get(servletFilterBuilder.getTemplateId()));
}
return servletContextHandlerFactory;
});
addFactory(builder,updateableServletFactoryTemplateId, Scope.SINGLETON, (ctx)->{
UpdateableServletFactory updateableServletFactory = new UpdateableServletFactory<>();
for (ResourceBuilder resourceBuilder : resourceBuilders) {
updateableServletFactory.servletAndPaths.add(ctx.get(resourceBuilder.getServletAndPathFactoryTemplateId()));
}
for (ServletBuilder servletBuilder : additionalServletBuilders) {
updateableServletFactory.servletAndPaths.add(ctx.get(servletBuilder.getTemplateId()));
}
return updateableServletFactory;
});
for (ResourceBuilder resourceBuilder : resourceBuilders) {
resourceBuilder.build(builder);
}
for (ServletBuilder servletBuilder : additionalServletBuilders) {
servletBuilder.build(builder);
}
for (ServletFilterBuilder filterBuilder : servletFilterBuilders) {
filterBuilder.build(builder);
}
}
private void addResourceBuilder(ResourceBuilder resourceBuilder){
for (ResourceBuilder builder : resourceBuilders) {
if (builder.match(resourceBuilder)){
throw new IllegalStateException("can't add multiple jersey servlets with the same patchSpec");
}
}
resourceBuilders.add(resourceBuilder);
}
private ServerConnectorBuilder getDefaultServerConnector(){
if (this.defaultServerConnector==null){
this.defaultServerConnector=new ServerConnectorBuilder<>(defaultServerConnectorTemplateId);
serverConnectorBuilders.add(defaultServerConnector);
}
return this.defaultServerConnector;
}
/**
* @see ServerConnectorBuilder#withPort(int)
* @param port port
* @return builder
*/
public JettyServerBuilder withPort(int port){
getDefaultServerConnector().withPort(port);
return this;
}
/**
* @see ServerConnectorBuilder#withHost(String)
* @param host host
* @return builder
*/
public JettyServerBuilder withHost(String host){
getDefaultServerConnector().withHost(host);
return this;
}
/**
* @see ServerConnectorBuilder#withHostWildcard()
* @return builder
*/
public JettyServerBuilder withHostWildcard(){
getDefaultServerConnector().withHostWildcard();
return this;
}
/**
* @see ServerConnectorBuilder#withSsl(FactoryBase)
* @param ssl ssl
* @return builder
*/
public JettyServerBuilder withSsl(FactoryBase ssl) {
getDefaultServerConnector().withSsl(ssl);
return this;
}
/**
* @see ServerConnectorBuilder#withHttpConfiguration(HttpConfigurationFactory)
* @param httpConfiguration httpConfiguration
* @return builder
*/
public JettyServerBuilder withHttpConfiguration(HttpConfigurationFactory httpConfiguration) {
getDefaultServerConnector().withHttpConfiguration(httpConfiguration);
return this;
}
/**
* @see ServerConnectorBuilder#withRandomPort()
* @return builder
*/
public JettyServerBuilder withRandomPort(){
getDefaultServerConnector().withRandomPort();
return this;
}
private ResourceBuilder getDefaultJersey(){
if (this.resourceBuilder==null){
this.resourceBuilder=new ResourceBuilder<>(new FactoryTemplateId<>(this.rootTemplateId.name+"DefaultResource", ServletAndPathFactory.class));
addResourceBuilder(resourceBuilder);
}
return this.resourceBuilder;
}
/**
* @see ResourceBuilder#withPathSpec(String)
* @param pathSpec pathSpec
* @return builder
*/
public JettyServerBuilder withPathSpec(String pathSpec){
getDefaultJersey().withPathSpec(pathSpec);
return this;
}
/**
* add a new Resource to the default jersey servlet
* @see ResourceBuilder#withResource(FactoryBase)
* @param resource resource
* @return builder
*/
public JettyServerBuilder withResource(FactoryBase,R> resource){
getDefaultJersey().withResource(resource);
return this;
}
/**
* @see ResourceBuilder#withJaxrsComponent(FactoryBase)
* @param jaxrsComponent jaxrsComponent
* @return builder
*/
public JettyServerBuilder withJaxrsComponent(FactoryBase,R> jaxrsComponent){
getDefaultJersey().withJaxrsComponent(jaxrsComponent);
return this;
}
/**
* @see ResourceBuilder#withLoggingFeature(FactoryBase)
* @param loggingFeature loggingFeature
* @return builder
*/
public JettyServerBuilder withLoggingFeature(FactoryBase loggingFeature){
getDefaultJersey().withLoggingFeature(loggingFeature);
return this;
}
/**
* @see ResourceBuilder#withObjectMapper(FactoryBase)
* @param objectMapper objectMapper
* @return builder
*/
public JettyServerBuilder withObjectMapper(FactoryBase objectMapper){
getDefaultJersey().withObjectMapper(objectMapper);
return this;
}
/**
* @see ResourceBuilder#withExceptionMapper(FactoryBase)
* @param exceptionMapper exceptionMapper
* @return builder
*/
public JettyServerBuilder withExceptionMapper(FactoryBase,R> exceptionMapper) {
getDefaultJersey().withExceptionMapper(exceptionMapper);
return this;
}
/**
* @see ResourceBuilder#withJerseyProperties(Map)
* @param jerseyProperties jerseyProperties
* @return builder
*/
public JettyServerBuilder withJerseyProperties(Map jerseyProperties) {
getDefaultJersey().withJerseyProperties(jerseyProperties);
return this;
}
/**
* @see ServerConnectorBuilder#withHttp2()
* @return builder
*/
public JettyServerBuilder withHttp2() {
getDefaultServerConnector().withHttp2();
return this;
}
}