All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.factoryfx.jetty.builder.JettyServerBuilder Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
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 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 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 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 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 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 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 resource){ getDefaultJersey().withResource(resource); return this; } /** * @see ResourceBuilder#withJaxrsComponent(FactoryBase) * @param jaxrsComponent jaxrsComponent * @return builder */ public JettyServerBuilder withJaxrsComponent(FactoryBase 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy