Commit b1c689b9 authored by Phillip Webb's avatar Phillip Webb

Unify WebServerFactory implementations

Unify common for from the abstract `ServletWebServerFactory` and
`ReactiveWebServerFactory` classes. Common code is now located in
`AbstractConfigurableWebServerFactory`.

Fixes gh-8631
parent 099e188f
......@@ -26,7 +26,7 @@ import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.client.TestRestTemplate.HttpClientOption;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.web.servlet.server.AbstractConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
......@@ -106,8 +106,8 @@ class SpringBootTestContextCustomizer implements ContextCustomizer {
private boolean isSslEnabled(ApplicationContext context) {
try {
AbstractConfigurableServletWebServerFactory webServerFactory = context
.getBean(AbstractConfigurableServletWebServerFactory.class);
AbstractServletWebServerFactory webServerFactory = context
.getBean(AbstractServletWebServerFactory.class);
return webServerFactory.getSsl() != null
&& webServerFactory.getSsl().isEnabled();
}
......
......@@ -23,7 +23,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.reactive.server.AbstractConfigurableReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
......@@ -120,9 +120,10 @@ class WebTestClientContextCustomizer implements ContextCustomizer {
private boolean isSslEnabled(ApplicationContext context) {
try {
AbstractConfigurableReactiveWebServerFactory webServerFactory = context
.getBean(AbstractConfigurableReactiveWebServerFactory.class);
return webServerFactory.getSsl() != null && webServerFactory.getSsl().isEnabled();
AbstractReactiveWebServerFactory webServerFactory = context
.getBean(AbstractReactiveWebServerFactory.class);
return webServerFactory.getSsl() != null
&& webServerFactory.getSsl().isEnabled();
}
catch (NoSuchBeanDefinitionException ex) {
return false;
......
......@@ -18,6 +18,8 @@ package org.springframework.boot.web.embedded.jetty;
import java.net.InetSocketAddress;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.HttpConfiguration;
......@@ -41,6 +43,9 @@ import org.springframework.http.server.reactive.JettyHttpHandlerAdapter;
*/
public class JettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory {
private static final Log logger = LogFactory
.getLog(JettyReactiveWebServerFactory.class);
/**
* The number of acceptor threads to use.
*/
......@@ -85,7 +90,8 @@ public class JettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
ServletContextHandler contextHandler = new ServletContextHandler(server, "",
false, false);
contextHandler.addServlet(servletHolder, "/");
this.logger.info("Server initialized with port: " + port);
JettyReactiveWebServerFactory.logger
.info("Server initialized with port: " + port);
return server;
}
......
......@@ -16,13 +16,7 @@
package org.springframework.boot.web.reactive.server;
import java.io.File;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.web.server.WebServerException;
import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;
/**
* Abstract base class for {@link ReactiveWebServerFactory} implementations.
......@@ -30,10 +24,9 @@ import org.springframework.boot.web.server.WebServerException;
* @author Brian Clozel
* @since 2.0.0
*/
public abstract class AbstractReactiveWebServerFactory extends
AbstractConfigurableReactiveWebServerFactory implements ReactiveWebServerFactory {
protected final Log logger = LogFactory.getLog(getClass());
public abstract class AbstractReactiveWebServerFactory
extends AbstractConfigurableWebServerFactory
implements ConfigurableReactiveWebServerFactory {
public AbstractReactiveWebServerFactory() {
}
......@@ -42,25 +35,4 @@ public abstract class AbstractReactiveWebServerFactory extends
super(port);
}
/**
* Return the absolute temp dir for given web server.
* @param prefix server name
* @return The temp dir for given server.
*/
protected File createTempDir(String prefix) {
try {
File tempDir = File.createTempFile(prefix + ".", "." + getPort());
tempDir.delete();
tempDir.mkdir();
tempDir.deleteOnExit();
return tempDir;
}
catch (IOException ex) {
throw new WebServerException(
"Unable to create tempDir. java.io.tmpdir is set to "
+ System.getProperty("java.io.tmpdir"),
ex);
}
}
}
......@@ -19,11 +19,12 @@ package org.springframework.boot.web.reactive.server;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
/**
* Interface that represents customizations to a {@link ReactiveWebServerFactory}.
* Configurable {@link ReactiveWebServerFactory}.
*
* @author Brian Clozel
* @since 2.0.0
*/
public interface ConfigurableReactiveWebServerFactory extends ConfigurableWebServerFactory {
public interface ConfigurableReactiveWebServerFactory
extends ConfigurableWebServerFactory, ReactiveWebServerFactory {
}
......@@ -14,34 +14,38 @@
* limitations under the License.
*/
package org.springframework.boot.web.reactive.server;
package org.springframework.boot.web.server;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import org.springframework.boot.web.server.Compression;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.server.SslStoreProvider;
import org.springframework.util.Assert;
/**
* Abstract base class for {@link ConfigurableReactiveWebServerFactory} implementations.
* Abstract base class for {@link ConfigurableWebServerFactory} implementations.
*
* @author Phillip Webb
* @author Dave Syer
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Ivan Sopov
* @author Eddú Meléndez
* @author Brian Clozel
* @since 2.0.0
*/
public class AbstractConfigurableReactiveWebServerFactory
implements ConfigurableReactiveWebServerFactory {
public class AbstractConfigurableWebServerFactory
implements ConfigurableWebServerFactory {
private int port = 8080;
private Set<ErrorPage> errorPages = new LinkedHashSet<>();
private InetAddress address;
private Set<ErrorPage> errorPages = new LinkedHashSet<>();
private Ssl ssl;
private SslStoreProvider sslStoreProvider;
......@@ -51,27 +55,35 @@ public class AbstractConfigurableReactiveWebServerFactory
private String serverHeader;
/**
* Create a new {@link AbstractConfigurableReactiveWebServerFactory} instance.
* Create a new {@link AbstractConfigurableWebServerFactory} instance.
*/
public AbstractConfigurableReactiveWebServerFactory() {
public AbstractConfigurableWebServerFactory() {
}
/**
* Create a new {@link AbstractConfigurableReactiveWebServerFactory} instance with the
* Create a new {@link AbstractConfigurableWebServerFactory} instance with the
* specified port.
* @param port the port number for the reactive web server
* @param port the port number for the web server
*/
public AbstractConfigurableReactiveWebServerFactory(int port) {
public AbstractConfigurableWebServerFactory(int port) {
this.port = port;
}
/**
* The port that the web server server listens on.
* @return the port
*/
public int getPort() {
return this.port;
}
@Override
public void setAddress(InetAddress address) {
this.address = address;
public void setPort(int port) {
this.port = port;
}
/**
* Return the address that the reactive web server binds to.
* Return the address that the web server binds to.
* @return the address
*/
public InetAddress getAddress() {
......@@ -79,16 +91,17 @@ public class AbstractConfigurableReactiveWebServerFactory
}
@Override
public void setPort(int port) {
this.port = port;
public void setAddress(InetAddress address) {
this.address = address;
}
/**
* The port that the reactive web server listens on.
* @return the port
* Returns a mutable set of {@link ErrorPage ErrorPages} that will be used when
* handling exceptions.
* @return the error pages
*/
public int getPort() {
return this.port;
public Set<ErrorPage> getErrorPages() {
return this.errorPages;
}
@Override
......@@ -103,13 +116,8 @@ public class AbstractConfigurableReactiveWebServerFactory
this.errorPages.addAll(Arrays.asList(errorPages));
}
/**
* Return a mutable set of {@link ErrorPage ErrorPages} that will be used when
* handling exceptions.
* @return the error pages
*/
public Set<ErrorPage> getErrorPages() {
return this.errorPages;
public Ssl getSsl() {
return this.ssl;
}
@Override
......@@ -117,8 +125,8 @@ public class AbstractConfigurableReactiveWebServerFactory
this.ssl = ssl;
}
public Ssl getSsl() {
return this.ssl;
public SslStoreProvider getSslStoreProvider() {
return this.sslStoreProvider;
}
@Override
......@@ -126,10 +134,6 @@ public class AbstractConfigurableReactiveWebServerFactory
this.sslStoreProvider = sslStoreProvider;
}
public SslStoreProvider getSslStoreProvider() {
return this.sslStoreProvider;
}
public Compression getCompression() {
return this.compression;
}
......@@ -148,4 +152,25 @@ public class AbstractConfigurableReactiveWebServerFactory
this.serverHeader = serverHeader;
}
/**
* Return the absolute temp dir for given web server.
* @param prefix server name
* @return The temp dir for given server.
*/
protected final File createTempDir(String prefix) {
try {
File tempDir = File.createTempFile(prefix + ".", "." + getPort());
tempDir.delete();
tempDir.mkdir();
tempDir.deleteOnExit();
return tempDir;
}
catch (IOException ex) {
throw new WebServerException(
"Unable to create tempDir. java.io.tmpdir is set to "
+ System.getProperty("java.io.tmpdir"),
ex);
}
}
}
......@@ -20,11 +20,12 @@ import java.net.InetAddress;
import java.util.Set;
/**
* Simple interface that represents customizations to a {@link WebServerFactory}.
* A configurable {@link WebServerFactory}.
*
* @author Phillip Webb
* @author Brian Clozel
* @since 2.0.0
* @see ErrorPageRegistry
*/
public interface ConfigurableWebServerFactory
extends WebServerFactory, ErrorPageRegistry {
......
......@@ -22,10 +22,15 @@ import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.jar.JarFile;
import org.apache.commons.logging.Log;
......@@ -33,34 +38,258 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.boot.ApplicationHome;
import org.springframework.boot.ApplicationTemp;
import org.springframework.boot.web.server.WebServerException;
import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;
import org.springframework.boot.web.server.MimeMappings;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Abstract base class for {@link ServletWebServerFactory} implementations.
* Abstract base class for {@link ConfigurableServletWebServerFactory} implementations.
*
* @author Phillip Webb
* @author Dave Syer
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Ivan Sopov
* @author Eddú Meléndez
* @author Brian Clozel
* @since 2.0.0
*/
public abstract class AbstractServletWebServerFactory extends
AbstractConfigurableServletWebServerFactory implements ServletWebServerFactory {
public abstract class AbstractServletWebServerFactory
extends AbstractConfigurableWebServerFactory
implements ConfigurableServletWebServerFactory {
protected final Log logger = LogFactory.getLog(getClass());
private static final int DEFAULT_SESSION_TIMEOUT = (int) TimeUnit.MINUTES
.toSeconds(30);
private static final String[] COMMON_DOC_ROOTS = { "src/main/webapp", "public",
"static" };
protected final Log logger = LogFactory.getLog(getClass());
private String contextPath = "";
private String displayName;
private int sessionTimeout = DEFAULT_SESSION_TIMEOUT;
private boolean persistSession;
private File sessionStoreDir;
private boolean registerDefaultServlet = true;
private MimeMappings mimeMappings = new MimeMappings(MimeMappings.DEFAULT);
private File documentRoot;
private List<ServletContextInitializer> initializers = new ArrayList<>();
private Jsp jsp = new Jsp();
private Map<Locale, Charset> localeCharsetMappings = new HashMap<>();
/**
* Create a new {@link AbstractServletWebServerFactory} instance.
*/
public AbstractServletWebServerFactory() {
super();
}
/**
* Create a new {@link AbstractServletWebServerFactory} instance with the specified
* port.
* @param port the port number for the web server
*/
public AbstractServletWebServerFactory(int port) {
super(port);
}
/**
* Create a new {@link AbstractServletWebServerFactory} instance with the specified
* context path and port.
* @param contextPath the context path for the web server
* @param port the port number for the web server
*/
public AbstractServletWebServerFactory(String contextPath, int port) {
super(contextPath, port);
super(port);
checkContextPath(contextPath);
this.contextPath = contextPath;
}
/**
* Returns the context path for the web server. The path will start with "/" and not
* end with "/". The root context is represented by an empty string.
* @return the context path
*/
public String getContextPath() {
return this.contextPath;
}
@Override
public void setContextPath(String contextPath) {
checkContextPath(contextPath);
this.contextPath = contextPath;
}
private void checkContextPath(String contextPath) {
Assert.notNull(contextPath, "ContextPath must not be null");
if (contextPath.length() > 0) {
if ("/".equals(contextPath)) {
throw new IllegalArgumentException(
"Root ContextPath must be specified using an empty string");
}
if (!contextPath.startsWith("/") || contextPath.endsWith("/")) {
throw new IllegalArgumentException(
"ContextPath must start with '/' and not end with '/'");
}
}
}
public String getDisplayName() {
return this.displayName;
}
@Override
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
/**
* Return the session timeout in seconds.
* @return the timeout in seconds
*/
public int getSessionTimeout() {
return this.sessionTimeout;
}
@Override
public void setSessionTimeout(int sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
@Override
public void setSessionTimeout(int sessionTimeout, TimeUnit timeUnit) {
Assert.notNull(timeUnit, "TimeUnit must not be null");
this.sessionTimeout = (int) timeUnit.toSeconds(sessionTimeout);
}
public boolean isPersistSession() {
return this.persistSession;
}
@Override
public void setPersistSession(boolean persistSession) {
this.persistSession = persistSession;
}
public File getSessionStoreDir() {
return this.sessionStoreDir;
}
@Override
public void setSessionStoreDir(File sessionStoreDir) {
this.sessionStoreDir = sessionStoreDir;
}
/**
* Flag to indicate that the default servlet should be registered.
* @return true if the default servlet is to be registered
*/
public boolean isRegisterDefaultServlet() {
return this.registerDefaultServlet;
}
@Override
public void setRegisterDefaultServlet(boolean registerDefaultServlet) {
this.registerDefaultServlet = registerDefaultServlet;
}
/**
* Returns the mime-type mappings.
* @return the mimeMappings the mime-type mappings.
*/
public MimeMappings getMimeMappings() {
return this.mimeMappings;
}
@Override
public void setMimeMappings(MimeMappings mimeMappings) {
this.mimeMappings = new MimeMappings(mimeMappings);
}
/**
* Returns the document root which will be used by the web context to serve static
* files.
* @return the document root
*/
public File getDocumentRoot() {
return this.documentRoot;
}
@Override
public void setDocumentRoot(File documentRoot) {
this.documentRoot = documentRoot;
}
@Override
public void setInitializers(List<? extends ServletContextInitializer> initializers) {
Assert.notNull(initializers, "Initializers must not be null");
this.initializers = new ArrayList<>(initializers);
}
@Override
public void addInitializers(ServletContextInitializer... initializers) {
Assert.notNull(initializers, "Initializers must not be null");
this.initializers.addAll(Arrays.asList(initializers));
}
public Jsp getJsp() {
return this.jsp;
}
@Override
public void setJsp(Jsp jsp) {
this.jsp = jsp;
}
/**
* Return the Locale to Charset mappings.
* @return the charset mappings
*/
public Map<Locale, Charset> getLocaleCharsetMappings() {
return this.localeCharsetMappings;
}
@Override
public void setLocaleCharsetMappings(Map<Locale, Charset> localeCharsetMappings) {
Assert.notNull(localeCharsetMappings, "localeCharsetMappings must not be null");
this.localeCharsetMappings = localeCharsetMappings;
}
/**
* Utility method that can be used by subclasses wishing to combine the specified
* {@link ServletContextInitializer} parameters with those defined in this instance.
* @param initializers the initializers to merge
* @return a complete set of merged initializers (with the specified parameters
* appearing first)
*/
protected final ServletContextInitializer[] mergeInitializers(
ServletContextInitializer... initializers) {
List<ServletContextInitializer> mergedInitializers = new ArrayList<>();
mergedInitializers.addAll(Arrays.asList(initializers));
mergedInitializers.addAll(this.initializers);
return mergedInitializers
.toArray(new ServletContextInitializer[mergedInitializers.size()]);
}
/**
* Returns whether or not the JSP servlet should be registered with the web server.
* @return {@code true} if the servlet should be registered, otherwise {@code false}
*/
protected boolean shouldRegisterJspServlet() {
return this.jsp != null && this.jsp.getRegistered() && ClassUtils
.isPresent(this.jsp.getClassName(), getClass().getClassLoader());
}
/**
......@@ -152,7 +381,7 @@ public abstract class AbstractServletWebServerFactory extends
}
}
File getExplodedWarFileDocumentRoot(File codeSourceFile) {
protected final File getExplodedWarFileDocumentRoot(File codeSourceFile) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Code archive: " + codeSourceFile);
}
......@@ -236,25 +465,4 @@ public abstract class AbstractServletWebServerFactory extends
return dir;
}
/**
* Returns the absolute temp dir for given server.
* @param prefix server name
* @return The temp dir for given server.
*/
protected File createTempDir(String prefix) {
try {
File tempDir = File.createTempFile(prefix + ".", "." + getPort());
tempDir.delete();
tempDir.mkdir();
tempDir.deleteOnExit();
return tempDir;
}
catch (IOException ex) {
throw new WebServerException(
"Unable to create tempDir. java.io.tmpdir is set to "
+ System.getProperty("java.io.tmpdir"),
ex);
}
}
}
......@@ -29,7 +29,7 @@ import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.ServletContextInitializer;
/**
* Simple interface that represents customizations to an {@link ServletWebServerFactory}.
* A configurable {@link ServletWebServerFactory}.
*
* @author Dave Syer
* @author Andy Wilkinson
......@@ -41,7 +41,7 @@ import org.springframework.boot.web.servlet.ServletContextInitializer;
* @see WebServerFactoryCustomizer
*/
public interface ConfigurableServletWebServerFactory
extends ConfigurableWebServerFactory {
extends ConfigurableWebServerFactory, ServletWebServerFactory {
/**
* Sets the context path for the web server. The context should start with a "/"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment