This commit is contained in:
Phillip Webb 2014-11-18 15:40:24 -08:00
parent a6e4744c60
commit a641f0c72a
13 changed files with 125 additions and 134 deletions

View File

@ -42,4 +42,5 @@ public class SampleController {
public String foo() { public String foo() {
throw new IllegalArgumentException("Server error"); throw new IllegalArgumentException("Server error");
} }
} }

View File

@ -42,4 +42,5 @@ public class SampleController {
public String foo() { public String foo() {
throw new IllegalArgumentException("Server error"); throw new IllegalArgumentException("Server error");
} }
} }

View File

@ -36,4 +36,5 @@ public class SampleController {
public String helloWorld() { public String helloWorld() {
return this.cityService.getCity("Bath", "UK").getName(); return this.cityService.getCity("Bath", "UK").getName();
} }
} }

View File

@ -34,4 +34,5 @@ public class SampleController {
public String helloWorld() { public String helloWorld() {
return this.helloWorldService.getHelloMessage(); return this.helloWorldService.getHelloMessage();
} }
} }

View File

@ -34,4 +34,5 @@ public class SampleController {
public String helloWorld() { public String helloWorld() {
return this.helloWorldService.getHelloMessage(); return this.helloWorldService.getHelloMessage();
} }
} }

View File

@ -34,4 +34,5 @@ public class SampleController {
public String helloWorld() { public String helloWorld() {
return this.helloWorldService.getHelloMessage(); return this.helloWorldService.getHelloMessage();
} }
} }

View File

@ -34,4 +34,5 @@ public class SampleController {
public String helloWorld() { public String helloWorld() {
return this.helloWorldService.getHelloMessage(); return this.helloWorldService.getHelloMessage();
} }
} }

View File

@ -26,4 +26,5 @@ public class SampleController {
public String helloWorld() { public String helloWorld() {
return "hello"; return "hello";
} }
} }

View File

@ -34,4 +34,5 @@ public class SampleController {
public String helloWorld() { public String helloWorld() {
return this.helloWorldService.getHelloMessage(); return this.helloWorldService.getHelloMessage();
} }
} }

View File

@ -34,4 +34,5 @@ public class SampleController {
public String helloWorld() { public String helloWorld() {
return this.helloWorldService.getHelloMessage(); return this.helloWorldService.getHelloMessage();
} }
} }

View File

@ -20,7 +20,6 @@ import io.undertow.Handlers;
import io.undertow.Undertow; import io.undertow.Undertow;
import io.undertow.Undertow.Builder; import io.undertow.Undertow.Builder;
import io.undertow.server.HttpHandler; import io.undertow.server.HttpHandler;
import io.undertow.server.handlers.PathHandler;
import io.undertow.servlet.api.DeploymentManager; import io.undertow.servlet.api.DeploymentManager;
import javax.servlet.ServletException; import javax.servlet.ServletException;
@ -70,27 +69,32 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
return; return;
} }
if (this.undertow == null) { if (this.undertow == null) {
try { this.undertow = createUndertowServer();
HttpHandler servletHandler = this.manager.start();
if (StringUtils.isEmpty(this.contextPath)) {
this.builder.setHandler(servletHandler);
}
else {
PathHandler pathHandler = Handlers.path().addPrefixPath(
this.contextPath, servletHandler);
this.builder.setHandler(pathHandler);
}
this.undertow = this.builder.build();
}
catch (ServletException ex) {
throw new EmbeddedServletContainerException(
"Unable to start embdedded Undertow", ex);
}
} }
this.undertow.start(); this.undertow.start();
this.started = true; this.started = true;
} }
private Undertow createUndertowServer() {
try {
HttpHandler servletHandler = this.manager.start();
this.builder.setHandler(getContextHandler(servletHandler));
return this.builder.build();
}
catch (ServletException ex) {
throw new EmbeddedServletContainerException(
"Unable to start embdedded Undertow", ex);
}
}
private HttpHandler getContextHandler(HttpHandler servletHandler) {
if (StringUtils.isEmpty(this.contextPath)) {
return servletHandler;
}
return Handlers.path().addPrefixPath(this.contextPath, servletHandler);
}
@Override @Override
public synchronized void stop() throws EmbeddedServletContainerException { public synchronized void stop() throws EmbeddedServletContainerException {
if (this.started) { if (this.started) {
@ -104,4 +108,4 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
return this.port; return this.port;
} }
} }

View File

@ -25,15 +25,15 @@ import io.undertow.server.handlers.resource.Resource;
import io.undertow.server.handlers.resource.ResourceChangeListener; import io.undertow.server.handlers.resource.ResourceChangeListener;
import io.undertow.server.handlers.resource.ResourceManager; import io.undertow.server.handlers.resource.ResourceManager;
import io.undertow.server.handlers.resource.URLResource; import io.undertow.server.handlers.resource.URLResource;
import io.undertow.server.session.SessionManager;
import io.undertow.servlet.Servlets;
import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.DeploymentManager; import io.undertow.servlet.api.DeploymentManager;
import io.undertow.servlet.api.InstanceFactory;
import io.undertow.servlet.api.InstanceHandle;
import io.undertow.servlet.api.ListenerInfo; import io.undertow.servlet.api.ListenerInfo;
import io.undertow.servlet.api.MimeMapping; import io.undertow.servlet.api.MimeMapping;
import io.undertow.servlet.api.ServletStackTraces; import io.undertow.servlet.api.ServletStackTraces;
import io.undertow.servlet.handlers.DefaultServlet; import io.undertow.servlet.handlers.DefaultServlet;
import io.undertow.servlet.util.ImmediateInstanceHandle; import io.undertow.servlet.util.ImmediateInstanceFactory;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -68,14 +68,8 @@ import org.springframework.core.io.ResourceLoader;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
import org.springframework.util.SocketUtils; import org.springframework.util.SocketUtils;
import org.xnio.Options;
import static io.undertow.servlet.Servlets.defaultContainer; import org.xnio.SslClientAuthMode;
import static io.undertow.servlet.Servlets.deployment;
import static io.undertow.servlet.Servlets.servlet;
import static org.xnio.Options.SSL_CLIENT_AUTH_MODE;
import static org.xnio.SslClientAuthMode.NOT_REQUESTED;
import static org.xnio.SslClientAuthMode.REQUESTED;
import static org.xnio.SslClientAuthMode.REQUIRED;
/** /**
* {@link EmbeddedServletContainerFactory} that can be used to create * {@link EmbeddedServletContainerFactory} that can be used to create
@ -173,14 +167,11 @@ public class UndertowEmbeddedServletContainerFactory extends
public EmbeddedServletContainer getEmbeddedServletContainer( public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) { ServletContextInitializer... initializers) {
DeploymentManager manager = createDeploymentManager(initializers); DeploymentManager manager = createDeploymentManager(initializers);
int port = getPort(); int port = getPort();
if (port == 0) { if (port == 0) {
port = SocketUtils.findAvailableTcpPort(40000); port = SocketUtils.findAvailableTcpPort(40000);
} }
Builder builder = createBuilder(port); Builder builder = createBuilder(port);
return new UndertowEmbeddedServletContainer(builder, manager, getContextPath(), return new UndertowEmbeddedServletContainer(builder, manager, getContextPath(),
port, port >= 0); port, port >= 0);
} }
@ -202,7 +193,6 @@ public class UndertowEmbeddedServletContainerFactory extends
if (this.directBuffers != null) { if (this.directBuffers != null) {
builder.setDirectBuffers(this.directBuffers); builder.setDirectBuffers(this.directBuffers);
} }
if (getSsl() == null) { if (getSsl() == null) {
builder.addHttpListener(port, "0.0.0.0"); builder.addHttpListener(port, "0.0.0.0");
} }
@ -221,28 +211,30 @@ public class UndertowEmbeddedServletContainerFactory extends
SSLContext sslContext = SSLContext.getInstance(ssl.getProtocol()); SSLContext sslContext = SSLContext.getInstance(ssl.getProtocol());
sslContext.init(getKeyManagers(), getTrustManagers(), null); sslContext.init(getKeyManagers(), getTrustManagers(), null);
builder.addHttpsListener(port, "0.0.0.0", sslContext); builder.addHttpsListener(port, "0.0.0.0", sslContext);
if (ssl.getClientAuth() == ClientAuth.NEED) { builder.setSocketOption(Options.SSL_CLIENT_AUTH_MODE,
builder.setSocketOption(SSL_CLIENT_AUTH_MODE, REQUIRED); getSslClientAuthMode(ssl));
}
else if (ssl.getClientAuth() == ClientAuth.WANT) {
builder.setSocketOption(SSL_CLIENT_AUTH_MODE, REQUESTED);
}
else {
builder.setSocketOption(SSL_CLIENT_AUTH_MODE, NOT_REQUESTED);
}
} }
catch (NoSuchAlgorithmException ex) { catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex); throw new IllegalStateException(ex);
} }
catch (KeyManagementException ex) { catch (KeyManagementException ex) {
throw new RuntimeException(ex); throw new IllegalStateException(ex);
} }
} }
private SslClientAuthMode getSslClientAuthMode(Ssl ssl) {
if (ssl.getClientAuth() == ClientAuth.NEED) {
return SslClientAuthMode.REQUIRED;
}
if (ssl.getClientAuth() == ClientAuth.WANT) {
return SslClientAuthMode.REQUESTED;
}
return SslClientAuthMode.NOT_REQUESTED;
}
private KeyManager[] getKeyManagers() { private KeyManager[] getKeyManagers() {
try { try {
Ssl ssl = getSsl(); Ssl ssl = getSsl();
String keyStoreType = ssl.getKeyStoreType(); String keyStoreType = ssl.getKeyStoreType();
if (keyStoreType == null) { if (keyStoreType == null) {
keyStoreType = "JKS"; keyStoreType = "JKS";
@ -260,14 +252,13 @@ public class UndertowEmbeddedServletContainerFactory extends
return keyManagerFactory.getKeyManagers(); return keyManagerFactory.getKeyManagers();
} }
catch (Exception ex) { catch (Exception ex) {
throw new RuntimeException(ex); throw new IllegalStateException(ex);
} }
} }
private TrustManager[] getTrustManagers() { private TrustManager[] getTrustManagers() {
try { try {
Ssl ssl = getSsl(); Ssl ssl = getSsl();
String trustStoreType = ssl.getTrustStoreType(); String trustStoreType = ssl.getTrustStoreType();
if (trustStoreType == null) { if (trustStoreType == null) {
trustStoreType = "JKS"; trustStoreType = "JKS";
@ -280,88 +271,83 @@ public class UndertowEmbeddedServletContainerFactory extends
URL url = ResourceUtils.getURL(trustStore); URL url = ResourceUtils.getURL(trustStore);
trustedKeyStore.load(url.openStream(), ssl.getTrustStorePassword() trustedKeyStore.load(url.openStream(), ssl.getTrustStorePassword()
.toCharArray()); .toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm()); .getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustedKeyStore); trustManagerFactory.init(trustedKeyStore);
return trustManagerFactory.getTrustManagers(); return trustManagerFactory.getTrustManagers();
} }
catch (Exception ex) { catch (Exception ex) {
throw new RuntimeException(ex); throw new IllegalStateException(ex);
} }
} }
private DeploymentManager createDeploymentManager( private DeploymentManager createDeploymentManager(
ServletContextInitializer... initializers) { ServletContextInitializer... initializers) {
DeploymentInfo servletBuilder = deployment(); DeploymentInfo deployment = Servlets.deployment();
ServletContextInitializer[] mergeInitializers = mergeInitializers(initializers);
servletBuilder.addListener(new ListenerInfo( StartupListener startupListener = new StartupListener(mergeInitializers);
UndertowSpringServletContextListener.class, deployment.addListener(new ListenerInfo(StartupListener.class,
new UndertowSpringServletContextListenerFactory( new ImmediateInstanceFactory<StartupListener>(startupListener)));
new UndertowSpringServletContextListener( deployment.setClassLoader(getServletClassLoader());
mergeInitializers(initializers))))); deployment.setContextPath(getContextPath());
deployment.setDeploymentName("spring-boot");
if (this.resourceLoader != null) {
servletBuilder.setClassLoader(this.resourceLoader.getClassLoader());
}
else {
servletBuilder.setClassLoader(getClass().getClassLoader());
}
servletBuilder.setContextPath(getContextPath());
servletBuilder.setDeploymentName("spring-boot");
if (isRegisterDefaultServlet()) { if (isRegisterDefaultServlet()) {
servletBuilder.addServlet(servlet("default", DefaultServlet.class)); deployment.addServlet(Servlets.servlet("default", DefaultServlet.class));
} }
configureErrorPages(deployment);
deployment.setServletStackTraces(ServletStackTraces.NONE);
deployment.setResourceManager(getDocumentRootResourceManager());
configureMimeMappings(deployment);
DeploymentManager manager = Servlets.defaultContainer().addDeployment(deployment);
manager.deploy();
SessionManager sessionManager = manager.getDeployment().getSessionManager();
sessionManager.setDefaultSessionTimeout(getSessionTimeout());
return manager;
}
configureErrorPages(servletBuilder); private ClassLoader getServletClassLoader() {
servletBuilder.setServletStackTraces(ServletStackTraces.NONE); if (this.resourceLoader != null) {
return this.resourceLoader.getClassLoader();
}
return getClass().getClassLoader();
}
private ResourceManager getDocumentRootResourceManager() {
File root = getValidDocumentRoot(); File root = getValidDocumentRoot();
if (root != null && root.isDirectory()) { if (root != null && root.isDirectory()) {
servletBuilder.setResourceManager(new FileResourceManager(root, 0)); return new FileResourceManager(root, 0);
} }
else if (root != null && root.isFile()) { if (root != null && root.isFile()) {
servletBuilder.setResourceManager(new JarResourcemanager(root)); return new JarResourcemanager(root);
} }
else if (this.resourceLoader != null) { if (this.resourceLoader != null) {
servletBuilder.setResourceManager(new ClassPathResourceManager( return new ClassPathResourceManager(this.resourceLoader.getClassLoader(), "");
this.resourceLoader.getClassLoader(), ""));
} }
else { return new ClassPathResourceManager(getClass().getClassLoader(), "");
servletBuilder.setResourceManager(new ClassPathResourceManager(getClass()
.getClassLoader(), ""));
}
for (Mapping mimeMapping : getMimeMappings()) {
servletBuilder.addMimeMapping(new MimeMapping(mimeMapping.getExtension(),
mimeMapping.getMimeType()));
}
DeploymentManager manager = defaultContainer().addDeployment(servletBuilder);
manager.deploy();
manager.getDeployment().getSessionManager()
.setDefaultSessionTimeout(getSessionTimeout());
return manager;
} }
private void configureErrorPages(DeploymentInfo servletBuilder) { private void configureErrorPages(DeploymentInfo servletBuilder) {
for (ErrorPage errorPage : getErrorPages()) { for (ErrorPage errorPage : getErrorPages()) {
if (errorPage.getStatus() != null) { servletBuilder.addErrorPage(getUndertowErrorPage(errorPage));
io.undertow.servlet.api.ErrorPage undertowErrorpage = new io.undertow.servlet.api.ErrorPage( }
errorPage.getPath(), errorPage.getStatusCode()); }
servletBuilder.addErrorPage(undertowErrorpage);
} private io.undertow.servlet.api.ErrorPage getUndertowErrorPage(ErrorPage errorPage) {
else if (errorPage.getException() != null) { if (errorPage.getStatus() != null) {
io.undertow.servlet.api.ErrorPage undertowErrorpage = new io.undertow.servlet.api.ErrorPage( return new io.undertow.servlet.api.ErrorPage(errorPage.getPath(),
errorPage.getPath(), errorPage.getException()); errorPage.getStatusCode());
servletBuilder.addErrorPage(undertowErrorpage); }
} if (errorPage.getException() != null) {
else { return new io.undertow.servlet.api.ErrorPage(errorPage.getPath(),
io.undertow.servlet.api.ErrorPage undertowErrorpage = new io.undertow.servlet.api.ErrorPage( errorPage.getException());
errorPage.getPath()); }
servletBuilder.addErrorPage(undertowErrorpage); return new io.undertow.servlet.api.ErrorPage(errorPage.getPath());
} }
private void configureMimeMappings(DeploymentInfo servletBuilder) {
for (Mapping mimeMapping : getMimeMappings()) {
servletBuilder.addMimeMapping(new MimeMapping(mimeMapping.getExtension(),
mimeMapping.getMimeType()));
} }
} }
@ -370,7 +356,6 @@ public class UndertowEmbeddedServletContainerFactory extends
* Subclasses can override this method to return a different * Subclasses can override this method to return a different
* {@link UndertowEmbeddedServletContainer} or apply additional processing to the * {@link UndertowEmbeddedServletContainer} or apply additional processing to the
* {@link Builder} and {@link DeploymentManager} used to bootstrap Undertow * {@link Builder} and {@link DeploymentManager} used to bootstrap Undertow
*
* @param builder the builder * @param builder the builder
* @param manager the deployment manager * @param manager the deployment manager
* @param port the port that Undertow should listen on * @param port the port that Undertow should listen on
@ -413,7 +398,11 @@ public class UndertowEmbeddedServletContainerFactory extends
super.setRegisterJspServlet(registerJspServlet); super.setRegisterJspServlet(registerJspServlet);
} }
/**
* Undertow {@link ResourceManager} for JAR resources.
*/
private static class JarResourcemanager implements ResourceManager { private static class JarResourcemanager implements ResourceManager {
private final String jarPath; private final String jarPath;
public JarResourcemanager(File jarFile) { public JarResourcemanager(File jarFile) {
@ -424,11 +413,6 @@ public class UndertowEmbeddedServletContainerFactory extends
this.jarPath = jarPath; this.jarPath = jarPath;
} }
@Override
public void close() throws IOException {
// no code
}
@Override @Override
public Resource getResource(String path) throws IOException { public Resource getResource(String path) throws IOException {
URL url = new URL("jar:file:" + this.jarPath + "!" + path); URL url = new URL("jar:file:" + this.jarPath + "!" + path);
@ -453,36 +437,23 @@ public class UndertowEmbeddedServletContainerFactory extends
@Override @Override
public void removeResourceChangeListener(ResourceChangeListener listener) { public void removeResourceChangeListener(ResourceChangeListener listener) {
throw UndertowMessages.MESSAGES.resourceChangeListenerNotSupported(); throw UndertowMessages.MESSAGES.resourceChangeListenerNotSupported();
}
}
private static class UndertowSpringServletContextListenerFactory implements
InstanceFactory<UndertowSpringServletContextListener> {
private final UndertowSpringServletContextListener listener;
public UndertowSpringServletContextListenerFactory(
UndertowSpringServletContextListener listener) {
this.listener = listener;
} }
@Override @Override
public InstanceHandle<UndertowSpringServletContextListener> createInstance() public void close() throws IOException {
throws InstantiationException {
return new ImmediateInstanceHandle<UndertowSpringServletContextListener>(
this.listener);
} }
} }
private static class UndertowSpringServletContextListener implements /**
ServletContextListener { * {@link ServletContextListener} to trigger
* {@link ServletContextInitializer#onStartup(javax.servlet.ServletContext)}.
*/
private static class StartupListener implements ServletContextListener {
private final ServletContextInitializer[] initializers; private final ServletContextInitializer[] initializers;
public UndertowSpringServletContextListener( public StartupListener(ServletContextInitializer... initializers) {
ServletContextInitializer... initializers) {
this.initializers = initializers; this.initializers = initializers;
} }
@ -494,14 +465,14 @@ public class UndertowEmbeddedServletContainerFactory extends
} }
} }
catch (ServletException ex) { catch (ServletException ex) {
throw new RuntimeException(ex); throw new IllegalStateException(ex);
} }
} }
@Override @Override
public void contextDestroyed(ServletContextEvent sce) { public void contextDestroyed(ServletContextEvent sce) {
// no code
} }
} }
} }

View File

@ -93,4 +93,10 @@ public class UndertowEmbeddedServletContainerFactoryTests extends
ordered.verify(customizer).customize((Builder) anyObject()); ordered.verify(customizer).customize((Builder) anyObject());
} }
} }
@Test
public void basicSslClasspathKeyStore() throws Exception {
testBasicSllWithKeystore("classpath:test.jks");
}
} }