Skip to content

Commit 1458c7e

Browse files
committed
UndertowRequestUpgradeStrategy auto-adapts to Undertow 1.3's different Pool API
Issue: SPR-13494
1 parent 0510329 commit 1458c7e

File tree

1 file changed

+60
-30
lines changed

1 file changed

+60
-30
lines changed

spring-websocket/src/main/java/org/springframework/web/socket/server/standard/UndertowRequestUpgradeStrategy.java

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.web.socket.server.standard;
1818

1919
import java.lang.reflect.Constructor;
20+
import java.lang.reflect.Method;
2021
import java.util.Arrays;
2122
import java.util.Collections;
2223
import java.util.List;
@@ -48,57 +49,84 @@
4849
import io.undertow.websockets.jsr.handshake.JsrHybi07Handshake;
4950
import io.undertow.websockets.jsr.handshake.JsrHybi08Handshake;
5051
import io.undertow.websockets.jsr.handshake.JsrHybi13Handshake;
52+
import io.undertow.websockets.spi.WebSocketHttpExchange;
5153
import org.xnio.StreamConnection;
5254

5355
import org.springframework.http.server.ServerHttpRequest;
5456
import org.springframework.http.server.ServerHttpResponse;
5557
import org.springframework.util.ClassUtils;
58+
import org.springframework.util.ReflectionUtils;
5659
import org.springframework.web.socket.server.HandshakeFailureException;
5760

5861
/**
5962
* A {@link org.springframework.web.socket.server.RequestUpgradeStrategy} for use
6063
* with WildFly and its underlying Undertow web server.
6164
*
62-
* <p>Compatible with Undertow 1.0, 1.1, 1.2 - as included in WildFly 8.x and 9.0.
65+
* <p>Compatible with Undertow 1.0 to 1.3 - as included in WildFly 8.x, 9 and 10.
6366
*
6467
* @author Rossen Stoyanchev
68+
* @author Brian Clozel
69+
* @author Juergen Hoeller
6570
* @since 4.0.1
6671
*/
6772
public class UndertowRequestUpgradeStrategy extends AbstractStandardUpgradeStrategy {
6873

6974
private static final Constructor<ServletWebSocketHttpExchange> exchangeConstructor;
7075

76+
private static final boolean exchangeConstructorWithPeerConnections;
77+
7178
private static final Constructor<ConfiguredServerEndpoint> endpointConstructor;
7279

73-
private static final boolean undertow10Present;
80+
private static final boolean endpointConstructorWithEndpointFactory;
81+
82+
private static final Method getBufferPoolMethod;
7483

75-
private static final boolean undertow11Present;
84+
private static final Method createChannelMethod;
7685

7786
static {
78-
Class<ServletWebSocketHttpExchange> exchangeType = ServletWebSocketHttpExchange.class;
79-
Class<?>[] exchangeParamTypes = new Class<?>[] {HttpServletRequest.class, HttpServletResponse.class, Set.class};
80-
if (ClassUtils.hasConstructor(exchangeType, exchangeParamTypes)) {
81-
exchangeConstructor = ClassUtils.getConstructorIfAvailable(exchangeType, exchangeParamTypes);
82-
undertow10Present = false;
83-
}
84-
else {
85-
exchangeParamTypes = new Class<?>[] {HttpServletRequest.class, HttpServletResponse.class};
86-
exchangeConstructor = ClassUtils.getConstructorIfAvailable(exchangeType, exchangeParamTypes);
87-
undertow10Present = true;
88-
}
87+
try {
88+
Class<ServletWebSocketHttpExchange> exchangeType = ServletWebSocketHttpExchange.class;
89+
Class<?>[] exchangeParamTypes =
90+
new Class<?>[] {HttpServletRequest.class, HttpServletResponse.class, Set.class};
91+
Constructor<ServletWebSocketHttpExchange> exchangeCtor =
92+
ClassUtils.getConstructorIfAvailable(exchangeType, exchangeParamTypes);
93+
if (exchangeCtor != null) {
94+
// Undertow 1.1+
95+
exchangeConstructor = exchangeCtor;
96+
exchangeConstructorWithPeerConnections = true;
97+
}
98+
else {
99+
// Undertow 1.0
100+
exchangeParamTypes = new Class<?>[] {HttpServletRequest.class, HttpServletResponse.class};
101+
exchangeConstructor = exchangeType.getConstructor(exchangeParamTypes);
102+
exchangeConstructorWithPeerConnections = false;
103+
}
89104

90-
Class<ConfiguredServerEndpoint> endpointType = ConfiguredServerEndpoint.class;
91-
Class<?>[] endpointParamTypes = new Class<?>[] {ServerEndpointConfig.class, InstanceFactory.class,
92-
PathTemplate.class, EncodingFactory.class, AnnotatedEndpointFactory.class};
93-
if (ClassUtils.hasConstructor(endpointType, endpointParamTypes)) {
94-
endpointConstructor = ClassUtils.getConstructorIfAvailable(endpointType, endpointParamTypes);
95-
undertow11Present = true;
105+
Class<ConfiguredServerEndpoint> endpointType = ConfiguredServerEndpoint.class;
106+
Class<?>[] endpointParamTypes = new Class<?>[] {ServerEndpointConfig.class, InstanceFactory.class,
107+
PathTemplate.class, EncodingFactory.class, AnnotatedEndpointFactory.class};
108+
Constructor<ConfiguredServerEndpoint> endpointCtor =
109+
ClassUtils.getConstructorIfAvailable(endpointType, endpointParamTypes);
110+
if (endpointCtor != null) {
111+
// Undertow 1.1+
112+
endpointConstructor = endpointCtor;
113+
endpointConstructorWithEndpointFactory = true;
114+
}
115+
else {
116+
// Undertow 1.0
117+
endpointParamTypes = new Class<?>[] {ServerEndpointConfig.class, InstanceFactory.class,
118+
PathTemplate.class, EncodingFactory.class};
119+
endpointConstructor = endpointType.getConstructor(endpointParamTypes);
120+
endpointConstructorWithEndpointFactory = false;
121+
}
122+
123+
// Adapting between different Pool API types in Undertow 1.0-1.2 vs 1.3
124+
getBufferPoolMethod = WebSocketHttpExchange.class.getMethod("getBufferPool");
125+
createChannelMethod = Handshake.class.getMethod("createChannel",
126+
WebSocketHttpExchange.class, StreamConnection.class, getBufferPoolMethod.getReturnType());
96127
}
97-
else {
98-
endpointParamTypes = new Class<?>[] {ServerEndpointConfig.class, InstanceFactory.class,
99-
PathTemplate.class, EncodingFactory.class};
100-
endpointConstructor = ClassUtils.getConstructorIfAvailable(endpointType, endpointParamTypes);
101-
undertow11Present = false;
128+
catch (Throwable ex) {
129+
throw new IllegalStateException("Incompatible Undertow API version", ex);
102130
}
103131
}
104132

@@ -113,11 +141,11 @@ public class UndertowRequestUpgradeStrategy extends AbstractStandardUpgradeStrat
113141

114142

115143
public UndertowRequestUpgradeStrategy() {
116-
if (undertow10Present) {
117-
this.peerConnections = null;
144+
if (exchangeConstructorWithPeerConnections) {
145+
this.peerConnections = Collections.newSetFromMap(new ConcurrentHashMap<WebSocketChannel, Boolean>());
118146
}
119147
else {
120-
this.peerConnections = Collections.newSetFromMap(new ConcurrentHashMap<WebSocketChannel, Boolean>());
148+
this.peerConnections = null;
121149
}
122150
}
123151

@@ -149,7 +177,9 @@ protected void upgradeInternal(ServerHttpRequest request, ServerHttpResponse res
149177
exchange.upgradeChannel(new HttpUpgradeListener() {
150178
@Override
151179
public void handleUpgrade(StreamConnection connection, HttpServerExchange serverExchange) {
152-
WebSocketChannel channel = handshake.createChannel(exchange, connection, exchange.getBufferPool());
180+
Object bufferPool = ReflectionUtils.invokeMethod(getBufferPoolMethod, exchange);
181+
WebSocketChannel channel = (WebSocketChannel) ReflectionUtils.invokeMethod(
182+
createChannelMethod, handshake, exchange, connection, bufferPool);
153183
if (peerConnections != null) {
154184
peerConnections.add(channel);
155185
}
@@ -202,7 +232,7 @@ private ConfiguredServerEndpoint createConfiguredServerEndpoint(String selectedP
202232
Collections.<Class<?>, List<InstanceFactory<? extends Encoder>>>emptyMap(),
203233
Collections.<Class<?>, List<InstanceFactory<? extends Decoder>>>emptyMap());
204234
try {
205-
return (undertow11Present ?
235+
return (endpointConstructorWithEndpointFactory ?
206236
endpointConstructor.newInstance(endpointRegistration,
207237
new EndpointInstanceFactory(endpoint), null, encodingFactory, null) :
208238
endpointConstructor.newInstance(endpointRegistration,

0 commit comments

Comments
 (0)