Skip to content

Commit 778aa39

Browse files
committed
Add Undertow WebSocket auto-configuration
Fixes gh-2028
1 parent 5f2b60e commit 778aa39

File tree

8 files changed

+206
-26
lines changed

8 files changed

+206
-26
lines changed

spring-boot-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@
170170
<artifactId>undertow-servlet</artifactId>
171171
<optional>true</optional>
172172
</dependency>
173+
<dependency>
174+
<groupId>io.undertow</groupId>
175+
<artifactId>undertow-websockets-jsr</artifactId>
176+
<optional>true</optional>
177+
</dependency>
173178
<dependency>
174179
<groupId>org.freemarker</groupId>
175180
<artifactId>freemarker</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.websocket;
18+
19+
import io.undertow.servlet.api.DeploymentInfo;
20+
import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
21+
22+
import org.springframework.boot.context.embedded.undertow.UndertowDeploymentInfoCustomizer;
23+
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
24+
25+
/**
26+
* {@link WebSocketContainerCustomizer} for
27+
* {@link UndertowEmbeddedServletContainerFactory}.
28+
*
29+
* @author Phillip Webb
30+
* @since 1.2.0
31+
*/
32+
public class UndertowWebSocketContainerCustomizer extends
33+
WebSocketContainerCustomizer<UndertowEmbeddedServletContainerFactory> {
34+
35+
@Override
36+
protected void doCustomize(UndertowEmbeddedServletContainerFactory container) {
37+
WebsocketDeploymentInfoCustomizer customizer = new WebsocketDeploymentInfoCustomizer();
38+
container.addDeploymentInfoCustomizers(customizer);
39+
}
40+
41+
private static class WebsocketDeploymentInfoCustomizer implements
42+
UndertowDeploymentInfoCustomizer {
43+
44+
@Override
45+
public void customize(DeploymentInfo deploymentInfo) {
46+
WebSocketDeploymentInfo info = new WebSocketDeploymentInfo();
47+
deploymentInfo.addServletContextAttribute(
48+
WebSocketDeploymentInfo.ATTRIBUTE_NAME, info);
49+
}
50+
51+
}
52+
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/WebSocketAutoConfiguration.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,16 @@ public EmbeddedServletContainerCustomizer websocketContainerCustomizer() {
7575

7676
}
7777

78+
@Configuration
79+
@ConditionalOnClass(io.undertow.websockets.jsr.Bootstrap.class)
80+
static class UndertowWebSocketConfiguration {
81+
82+
@Bean
83+
@ConditionalOnMissingBean(name = "websocketContainerCustomizer")
84+
public EmbeddedServletContainerCustomizer websocketContainerCustomizer() {
85+
return new UndertowWebSocketContainerCustomizer();
86+
}
87+
88+
}
89+
7890
}

spring-boot-dependencies/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,11 @@
563563
<artifactId>undertow-servlet</artifactId>
564564
<version>${undertow.version}</version>
565565
</dependency>
566+
<dependency>
567+
<groupId>io.undertow</groupId>
568+
<artifactId>undertow-websockets-jsr</artifactId>
569+
<version>${undertow.version}</version>
570+
</dependency>
566571
<dependency>
567572
<groupId>javax.cache</groupId>
568573
<artifactId>cache-api</artifactId>

spring-boot-starters/spring-boot-starter-undertow/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
</exclusion>
3434
</exclusions>
3535
</dependency>
36+
<dependency>
37+
<groupId>io.undertow</groupId>
38+
<artifactId>undertow-websockets-jsr</artifactId>
39+
</dependency>
3640
<dependency>
3741
<groupId>javax.servlet</groupId>
3842
<artifactId>javax.servlet-api</artifactId>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.context.embedded.undertow;
18+
19+
import io.undertow.servlet.api.DeploymentInfo;
20+
21+
/**
22+
* Callback interface that can be used to customize an Undertow {@link DeploymentInfo}.
23+
*
24+
* @author Phillip Webb
25+
* @since 1.2.0
26+
* @see UndertowEmbeddedServletContainerFactory
27+
*/
28+
public interface UndertowDeploymentInfoCustomizer {
29+
30+
/**
31+
* @param deploymentInfo the {@code DeploymentInfo} to customize
32+
*/
33+
void customize(DeploymentInfo deploymentInfo);
34+
35+
}

spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@
8686
public class UndertowEmbeddedServletContainerFactory extends
8787
AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware {
8888

89-
private List<UndertowBuilderCustomizer> undertowBuilderCustomizers = new ArrayList<UndertowBuilderCustomizer>();
89+
private List<UndertowBuilderCustomizer> builderCustomizers = new ArrayList<UndertowBuilderCustomizer>();
90+
91+
private List<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers = new ArrayList<UndertowDeploymentInfoCustomizer>();
9092

9193
private ResourceLoader resourceLoader;
9294

@@ -132,35 +134,64 @@ public UndertowEmbeddedServletContainerFactory(String contextPath, int port) {
132134
/**
133135
* Set {@link UndertowBuilderCustomizer}s that should be applied to the Undertow
134136
* {@link Builder}. Calling this method will replace any existing customizers.
135-
* @param undertowBuilderCustomizers the customizers to set
137+
* @param customizers the customizers to set
136138
*/
137-
public void setUndertowBuilderCustomizers(
138-
Collection<? extends UndertowBuilderCustomizer> undertowBuilderCustomizers) {
139-
Assert.notNull(undertowBuilderCustomizers,
140-
"undertowBuilderCustomizers must not be null");
141-
this.undertowBuilderCustomizers = new ArrayList<UndertowBuilderCustomizer>(
142-
undertowBuilderCustomizers);
139+
public void setBuilderCustomizers(
140+
Collection<? extends UndertowBuilderCustomizer> customizers) {
141+
Assert.notNull(customizers, "Customizers must not be null");
142+
this.builderCustomizers = new ArrayList<UndertowBuilderCustomizer>(customizers);
143143
}
144144

145145
/**
146146
* Returns a mutable collection of the {@link UndertowBuilderCustomizer}s that will be
147147
* applied to the Undertow {@link Builder} .
148148
* @return the customizers that will be applied
149149
*/
150-
public Collection<UndertowBuilderCustomizer> getUndertowBuilderCustomizers() {
151-
return this.undertowBuilderCustomizers;
150+
public Collection<UndertowBuilderCustomizer> getBuilderCustomizers() {
151+
return this.builderCustomizers;
152152
}
153153

154154
/**
155155
* Add {@link UndertowBuilderCustomizer}s that should be used to customize the
156156
* Undertow {@link Builder}.
157-
* @param undertowBuilderCustomizers the customizers to add
157+
* @param customizers the customizers to add
158+
*/
159+
public void addBuilderCustomizers(UndertowBuilderCustomizer... customizers) {
160+
Assert.notNull(customizers, "Customizers must not be null");
161+
this.builderCustomizers.addAll(Arrays.asList(customizers));
162+
}
163+
164+
/**
165+
* Set {@link UndertowDeploymentInfoCustomizer}s that should be applied to the
166+
* Undertow {@link DeploymentInfo}. Calling this method will replace any existing
167+
* customizers.
168+
* @param customizers the customizers to set
158169
*/
159-
public void addUndertowBuilderCustomizers(
160-
UndertowBuilderCustomizer... undertowBuilderCustomizers) {
161-
Assert.notNull(undertowBuilderCustomizers,
162-
"undertowBuilderCustomizers must not be null");
163-
this.undertowBuilderCustomizers.addAll(Arrays.asList(undertowBuilderCustomizers));
170+
public void setDeploymentInfoCustomizers(
171+
Collection<? extends UndertowDeploymentInfoCustomizer> customizers) {
172+
Assert.notNull(customizers, "Customizers must not be null");
173+
this.deploymentInfoCustomizers = new ArrayList<UndertowDeploymentInfoCustomizer>(
174+
customizers);
175+
}
176+
177+
/**
178+
* Returns a mutable collection of the {@link UndertowDeploymentInfoCustomizer}s that
179+
* will be applied to the Undertow {@link DeploymentInfo} .
180+
* @return the customizers that will be applied
181+
*/
182+
public Collection<UndertowDeploymentInfoCustomizer> getDeploymentInfoCustomizers() {
183+
return this.deploymentInfoCustomizers;
184+
}
185+
186+
/**
187+
* Add {@link UndertowDeploymentInfoCustomizer}s that should be used to customize the
188+
* Undertow {@link DeploymentInfo}.
189+
* @param customizers the customizers to add
190+
*/
191+
public void addDeploymentInfoCustomizers(
192+
UndertowDeploymentInfoCustomizer... customizers) {
193+
Assert.notNull(customizers, "UndertowDeploymentInfoCustomizers must not be null");
194+
this.deploymentInfoCustomizers.addAll(Arrays.asList(customizers));
164195
}
165196

166197
@Override
@@ -199,7 +230,7 @@ private Builder createBuilder(int port) {
199230
else {
200231
configureSsl(port, builder);
201232
}
202-
for (UndertowBuilderCustomizer customizer : this.undertowBuilderCustomizers) {
233+
for (UndertowBuilderCustomizer customizer : this.builderCustomizers) {
203234
customizer.customize(builder);
204235
}
205236
return builder;
@@ -298,6 +329,9 @@ private DeploymentManager createDeploymentManager(
298329
deployment.setServletStackTraces(ServletStackTraces.NONE);
299330
deployment.setResourceManager(getDocumentRootResourceManager());
300331
configureMimeMappings(deployment);
332+
for (UndertowDeploymentInfoCustomizer customizer : this.deploymentInfoCustomizers) {
333+
customizer.customize(deployment);
334+
}
301335
DeploymentManager manager = Servlets.defaultContainer().addDeployment(deployment);
302336
manager.deploy();
303337
SessionManager sessionManager = manager.getDeployment().getSessionManager();

spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.context.embedded.undertow;
1818

1919
import io.undertow.Undertow.Builder;
20+
import io.undertow.servlet.api.DeploymentInfo;
2021

2122
import java.util.Arrays;
2223

@@ -62,19 +63,19 @@ public void errorPage404() throws Exception {
6263
}
6364

6465
@Test
65-
public void setNullUndertowBuilderCustomizersThrows() {
66+
public void setNullBuilderCustomizersThrows() {
6667
UndertowEmbeddedServletContainerFactory factory = getFactory();
6768
this.thrown.expect(IllegalArgumentException.class);
68-
this.thrown.expectMessage("undertowBuilderCustomizers must not be null");
69-
factory.setUndertowBuilderCustomizers(null);
69+
this.thrown.expectMessage("Customizers must not be null");
70+
factory.setBuilderCustomizers(null);
7071
}
7172

7273
@Test
73-
public void addNullContextCustomizersThrows() {
74+
public void addNullAddBuilderCustomizersThrows() {
7475
UndertowEmbeddedServletContainerFactory factory = getFactory();
7576
this.thrown.expect(IllegalArgumentException.class);
76-
this.thrown.expectMessage("undertowBuilderCustomizers must not be null");
77-
factory.addUndertowBuilderCustomizers((UndertowBuilderCustomizer[]) null);
77+
this.thrown.expectMessage("Customizers must not be null");
78+
factory.addBuilderCustomizers((UndertowBuilderCustomizer[]) null);
7879
}
7980

8081
@Test
@@ -84,16 +85,48 @@ public void builderCustomizers() throws Exception {
8485
for (int i = 0; i < customizers.length; i++) {
8586
customizers[i] = mock(UndertowBuilderCustomizer.class);
8687
}
87-
factory.setUndertowBuilderCustomizers(Arrays.asList(customizers[0],
88-
customizers[1]));
89-
factory.addUndertowBuilderCustomizers(customizers[2], customizers[3]);
88+
factory.setBuilderCustomizers(Arrays.asList(customizers[0], customizers[1]));
89+
factory.addBuilderCustomizers(customizers[2], customizers[3]);
9090
this.container = factory.getEmbeddedServletContainer();
9191
InOrder ordered = inOrder((Object[]) customizers);
9292
for (UndertowBuilderCustomizer customizer : customizers) {
9393
ordered.verify(customizer).customize((Builder) anyObject());
9494
}
9595
}
9696

97+
@Test
98+
public void setNullDeploymentInfoCustomizersThrows() {
99+
UndertowEmbeddedServletContainerFactory factory = getFactory();
100+
this.thrown.expect(IllegalArgumentException.class);
101+
this.thrown.expectMessage("Customizers must not be null");
102+
factory.setDeploymentInfoCustomizers(null);
103+
}
104+
105+
@Test
106+
public void addNullAddDeploymentInfoCustomizersThrows() {
107+
UndertowEmbeddedServletContainerFactory factory = getFactory();
108+
this.thrown.expect(IllegalArgumentException.class);
109+
this.thrown.expectMessage("Customizers must not be null");
110+
factory.addDeploymentInfoCustomizers((UndertowDeploymentInfoCustomizer[]) null);
111+
}
112+
113+
@Test
114+
public void deploymentInfo() throws Exception {
115+
UndertowEmbeddedServletContainerFactory factory = getFactory();
116+
UndertowDeploymentInfoCustomizer[] customizers = new UndertowDeploymentInfoCustomizer[4];
117+
for (int i = 0; i < customizers.length; i++) {
118+
customizers[i] = mock(UndertowDeploymentInfoCustomizer.class);
119+
}
120+
factory.setDeploymentInfoCustomizers(Arrays
121+
.asList(customizers[0], customizers[1]));
122+
factory.addDeploymentInfoCustomizers(customizers[2], customizers[3]);
123+
this.container = factory.getEmbeddedServletContainer();
124+
InOrder ordered = inOrder((Object[]) customizers);
125+
for (UndertowDeploymentInfoCustomizer customizer : customizers) {
126+
ordered.verify(customizer).customize((DeploymentInfo) anyObject());
127+
}
128+
}
129+
97130
@Test
98131
public void basicSslClasspathKeyStore() throws Exception {
99132
testBasicSllWithKeystore("classpath:test.jks");

0 commit comments

Comments
 (0)