Skip to content

Commit 3e807c2

Browse files
committed
Update WebLogicRequestUpgradeStrategy for WLS 12.2.1
Issue: SPR-13234
1 parent 1d60a6a commit 3e807c2

File tree

2 files changed

+154
-45
lines changed

2 files changed

+154
-45
lines changed

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

+26-20
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import java.lang.reflect.Method;
2222
import java.net.URI;
2323
import java.util.ArrayList;
24-
import java.util.Arrays;
24+
import java.util.Collections;
2525
import java.util.List;
2626
import java.util.Random;
2727
import javax.servlet.ServletException;
@@ -53,6 +53,8 @@
5353
import org.springframework.web.socket.WebSocketExtension;
5454
import org.springframework.web.socket.server.HandshakeFailureException;
5555

56+
import static org.glassfish.tyrus.spi.WebSocketEngine.UpgradeStatus.SUCCESS;
57+
5658
/**
5759
* A base class for {@code RequestUpgradeStrategy} implementations on top of
5860
* JSR-356 based servers which include Tyrus as their WebSocket engine.
@@ -96,6 +98,7 @@ public void upgradeInternal(ServerHttpRequest request, ServerHttpResponse respon
9698
TyrusServerContainer serverContainer = (TyrusServerContainer) getContainer(servletRequest);
9799
TyrusWebSocketEngine engine = (TyrusWebSocketEngine) serverContainer.getWebSocketEngine();
98100
Object tyrusEndpoint = null;
101+
boolean success;
99102

100103
try {
101104
// Shouldn't matter for processing but must be unique
@@ -107,29 +110,22 @@ public void upgradeInternal(ServerHttpRequest request, ServerHttpResponse respon
107110
RequestContext requestContext = createRequestContext(servletRequest, path, headers);
108111
TyrusUpgradeResponse upgradeResponse = new TyrusUpgradeResponse();
109112
UpgradeInfo upgradeInfo = engine.upgrade(requestContext, upgradeResponse);
110-
111-
switch (upgradeInfo.getStatus()) {
112-
case SUCCESS:
113-
if (logger.isTraceEnabled()) {
114-
logger.trace("Successful upgrade: " + upgradeResponse.getHeaders());
115-
}
116-
handleSuccess(servletRequest, servletResponse, upgradeInfo, upgradeResponse);
117-
break;
118-
case HANDSHAKE_FAILED:
119-
// Should never happen
120-
throw new HandshakeFailureException("Unexpected handshake failure: " + request.getURI());
121-
case NOT_APPLICABLE:
122-
// Should never happen
123-
throw new HandshakeFailureException("Unexpected handshake mapping failure: " + request.getURI());
113+
success = SUCCESS.equals(upgradeInfo.getStatus());
114+
if (success) {
115+
if (logger.isTraceEnabled()) {
116+
logger.trace("Successful upgrade: " + upgradeResponse.getHeaders());
117+
}
118+
handleSuccess(servletRequest, servletResponse, upgradeInfo, upgradeResponse);
124119
}
125120
}
126121
catch (Exception ex) {
122+
unregisterTyrusEndpoint(engine, tyrusEndpoint);
127123
throw new HandshakeFailureException("Error during handshake: " + request.getURI(), ex);
128124
}
129-
finally {
130-
if (tyrusEndpoint != null) {
131-
getEndpointHelper().unregister(engine, tyrusEndpoint);
132-
}
125+
126+
unregisterTyrusEndpoint(engine, tyrusEndpoint);
127+
if (!success) {
128+
throw new HandshakeFailureException("Unexpected handshake failure: " + request.getURI());
133129
}
134130
}
135131

@@ -138,7 +134,7 @@ private Object createTyrusEndpoint(Endpoint endpoint, String endpointPath, Strin
138134
throws DeploymentException {
139135

140136
ServerEndpointRegistration endpointConfig = new ServerEndpointRegistration(endpointPath, endpoint);
141-
endpointConfig.setSubprotocols(Arrays.asList(protocol));
137+
endpointConfig.setSubprotocols(Collections.singletonList(protocol));
142138
endpointConfig.setExtensions(extensions);
143139
return getEndpointHelper().createdEndpoint(endpointConfig, this.componentProvider, container, engine);
144140
}
@@ -157,6 +153,16 @@ private RequestContext createRequestContext(HttpServletRequest request, String e
157153
return context;
158154
}
159155

156+
private void unregisterTyrusEndpoint(TyrusWebSocketEngine engine, Object tyrusEndpoint) {
157+
if (tyrusEndpoint != null) {
158+
try {
159+
getEndpointHelper().unregister(engine, tyrusEndpoint);
160+
}
161+
catch (Throwable ex) {
162+
// ignore
163+
}
164+
}
165+
}
160166

161167
protected abstract TyrusEndpointHelper getEndpointHelper();
162168

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

+128-25
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,57 @@
3030
import javax.servlet.http.HttpServletResponse;
3131
import javax.websocket.CloseReason;
3232

33+
import org.glassfish.tyrus.core.TyrusEndpointWrapper;
3334
import org.glassfish.tyrus.core.TyrusUpgradeResponse;
35+
import org.glassfish.tyrus.core.TyrusWebSocketEngine;
3436
import org.glassfish.tyrus.core.Utils;
3537
import org.glassfish.tyrus.spi.Connection;
3638
import org.glassfish.tyrus.spi.WebSocketEngine.UpgradeInfo;
3739
import org.glassfish.tyrus.spi.Writer;
3840

3941
import org.springframework.beans.BeanWrapper;
4042
import org.springframework.beans.BeanWrapperImpl;
43+
import org.springframework.util.ClassUtils;
4144
import org.springframework.util.ReflectionUtils;
4245
import org.springframework.web.socket.server.HandshakeFailureException;
4346

4447
/**
45-
* A WebSocket {@code RequestUpgradeStrategy} for Oracle's WebLogic 12.1.3 and higher.
48+
* A WebSocket {@code RequestUpgradeStrategy} for Oracle's WebLogic.
49+
* Supports 12.1.3 and 12.2.1.0.
4650
*
4751
* @author Rossen Stoyanchev
4852
* @since 4.1
4953
*/
5054
public class WebLogicRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeStrategy {
5155

52-
private static final TyrusEndpointHelper endpointHelper = new Tyrus135EndpointHelper();
56+
private static ClassLoader classLoader = WebLogicRequestUpgradeStrategy.class.getClassLoader();
57+
58+
private static final boolean WLS_12_1_3 = isWebLogic1213();
59+
60+
private static final TyrusEndpointHelper endpointHelper = WLS_12_1_3 ?
61+
new Tyrus135EndpointHelper() : new Tyrus17EndpointHelper();
5362

5463
private static final TyrusMuxableWebSocketHelper webSocketHelper = new TyrusMuxableWebSocketHelper();
5564

5665
private static final WebLogicServletWriterHelper servletWriterHelper = new WebLogicServletWriterHelper();
5766

5867

68+
69+
private static boolean isWebLogic1213() {
70+
try {
71+
type("weblogic.websocket.tyrus.TyrusMuxableWebSocket").getDeclaredConstructor(
72+
type("weblogic.servlet.internal.MuxableSocketHTTP"));
73+
return true;
74+
}
75+
catch (NoSuchMethodException e) {
76+
return false;
77+
}
78+
catch (ClassNotFoundException ex) {
79+
throw new IllegalStateException("No compatible WebSocket version found", ex);
80+
}
81+
}
82+
83+
5984
@Override
6085
protected TyrusEndpointHelper getEndpointHelper() {
6186
return endpointHelper;
@@ -76,7 +101,7 @@ protected void handleSuccess(HttpServletRequest request, HttpServletResponse res
76101
Object nativeRequest = getNativeRequest(request);
77102
BeanWrapper beanWrapper = new BeanWrapperImpl(nativeRequest);
78103
Object httpSocket = beanWrapper.getPropertyValue("connection.connectionHandler.rawConnection");
79-
Object webSocket = webSocketHelper.newInstance(httpSocket);
104+
Object webSocket = webSocketHelper.newInstance(request, httpSocket);
80105
webSocketHelper.upgrade(webSocket, httpSocket, request.getServletContext());
81106

82107
response.flushBuffer();
@@ -96,6 +121,16 @@ private static Object getNativeRequest(ServletRequest request) {
96121
return request;
97122
}
98123

124+
private static Class<?> type(String className) throws ClassNotFoundException {
125+
return classLoader.loadClass(className);
126+
}
127+
128+
private static Method method(String className, String method, Class<?>... paramTypes)
129+
throws ClassNotFoundException, NoSuchMethodException {
130+
131+
return type(className).getDeclaredMethod(method, paramTypes);
132+
}
133+
99134

100135
private static final Connection.CloseListener noOpCloseListener = new Connection.CloseListener() {
101136

@@ -110,33 +145,47 @@ public void close(CloseReason reason) {
110145
*/
111146
private static class TyrusMuxableWebSocketHelper {
112147

113-
public static final Class<?> webSocketType;
148+
private static final Class<?> type;
149+
150+
private static final Constructor<?> constructor;
114151

115-
private static final Constructor<?> webSocketConstructor;
152+
private static final SubjectHelper subjectHelper;
116153

117-
private static final Method webSocketUpgradeMethod;
154+
private static final Method upgradeMethod;
118155

119-
private static final Method webSocketReadEventMethod;
156+
private static final Method readEventMethod;
120157

121158
static {
122159
try {
123-
ClassLoader classLoader = WebLogicRequestUpgradeStrategy.class.getClassLoader();
124-
Class<?> socketType = classLoader.loadClass("weblogic.socket.MuxableSocket");
125-
Class<?> httpSocketType = classLoader.loadClass("weblogic.servlet.internal.MuxableSocketHTTP");
126-
127-
webSocketType = classLoader.loadClass("weblogic.websocket.tyrus.TyrusMuxableWebSocket");
128-
webSocketConstructor = webSocketType.getDeclaredConstructor(httpSocketType);
129-
webSocketUpgradeMethod = webSocketType.getMethod("upgrade", socketType, ServletContext.class);
130-
webSocketReadEventMethod = webSocketType.getMethod("registerForReadEvent");
160+
type = type("weblogic.websocket.tyrus.TyrusMuxableWebSocket");
161+
if (WLS_12_1_3) {
162+
constructor = type.getDeclaredConstructor(type("weblogic.servlet.internal.MuxableSocketHTTP"));
163+
subjectHelper = null;
164+
}
165+
else {
166+
constructor = type.getDeclaredConstructor(
167+
type("weblogic.servlet.internal.MuxableSocketHTTP"),
168+
type("weblogic.websocket.tyrus.CoherenceServletFilterService"),
169+
type("weblogic.servlet.spi.SubjectHandle"));
170+
subjectHelper = new SubjectHelper();
171+
}
172+
173+
upgradeMethod = type.getMethod("upgrade", type("weblogic.socket.MuxableSocket"), ServletContext.class);
174+
175+
readEventMethod = type.getMethod("registerForReadEvent");
131176
}
132177
catch (Exception ex) {
133178
throw new IllegalStateException("No compatible WebSocket version found", ex);
134179
}
135180
}
136181

137-
private Object newInstance(Object httpSocket) {
182+
private Object newInstance(HttpServletRequest request, Object httpSocket) {
138183
try {
139-
return webSocketConstructor.newInstance(httpSocket);
184+
Object[] args = (WLS_12_1_3 ?
185+
new Object[] {httpSocket} :
186+
new Object[] {httpSocket, null, subjectHelper.getSubject(request)});
187+
188+
return constructor.newInstance(args);
140189
}
141190
catch (Exception ex) {
142191
throw new HandshakeFailureException("Failed to create TyrusMuxableWebSocket", ex);
@@ -145,7 +194,7 @@ private Object newInstance(Object httpSocket) {
145194

146195
private void upgrade(Object webSocket, Object httpSocket, ServletContext servletContext) {
147196
try {
148-
webSocketUpgradeMethod.invoke(webSocket, httpSocket, servletContext);
197+
upgradeMethod.invoke(webSocket, httpSocket, servletContext);
149198
}
150199
catch (Exception ex) {
151200
throw new HandshakeFailureException("Failed to upgrade TyrusMuxableWebSocket", ex);
@@ -154,14 +203,60 @@ private void upgrade(Object webSocket, Object httpSocket, ServletContext servlet
154203

155204
private void registerForReadEvent(Object webSocket) {
156205
try {
157-
webSocketReadEventMethod.invoke(webSocket);
206+
readEventMethod.invoke(webSocket);
158207
}
159208
catch (Exception ex) {
160209
throw new HandshakeFailureException("Failed to register WebSocket for read event", ex);
161210
}
162211
}
163212
}
164213

214+
private static class SubjectHelper {
215+
216+
private final Method securityContextMethod;
217+
218+
private final Method currentUserMethod;
219+
220+
private final Method providerMethod;
221+
222+
private final Method anonymousSubjectMethod;
223+
224+
225+
public SubjectHelper() {
226+
try {
227+
String className = "weblogic.servlet.internal.WebAppServletContext";
228+
securityContextMethod = method(className, "getSecurityContext");
229+
230+
className = "weblogic.servlet.security.internal.SecurityModule";
231+
currentUserMethod = method(className, "getCurrentUser",
232+
type("weblogic.servlet.security.internal.ServletSecurityContext"),
233+
HttpServletRequest.class);
234+
235+
className = "weblogic.servlet.security.internal.WebAppSecurity";
236+
providerMethod = method(className, "getProvider");
237+
anonymousSubjectMethod = providerMethod.getReturnType().getDeclaredMethod("getAnonymousSubject");
238+
}
239+
catch (Exception ex) {
240+
throw new IllegalStateException("No compatible WebSocket version found", ex);
241+
}
242+
}
243+
244+
public Object getSubject(HttpServletRequest request) {
245+
try {
246+
ServletContext servletContext = request.getServletContext();
247+
Object securityContext = securityContextMethod.invoke(servletContext);
248+
Object subject = currentUserMethod.invoke(null, securityContext, request);
249+
if (subject == null) {
250+
Object securityProvider = providerMethod.invoke(null);
251+
subject = anonymousSubjectMethod.invoke(securityProvider);
252+
}
253+
return subject;
254+
}
255+
catch (Exception ex) {
256+
throw new HandshakeFailureException("Failed to obtain SubjectHandle", ex);
257+
}
258+
}
259+
}
165260

166261
/**
167262
* Helps to create and invoke {@code weblogic.websocket.tyrus.TyrusServletWriter}.
@@ -172,12 +267,16 @@ private static class WebLogicServletWriterHelper {
172267

173268
static {
174269
try {
175-
ClassLoader loader = WebLogicRequestUpgradeStrategy.class.getClassLoader();
176-
Class<?> type = loader.loadClass("weblogic.websocket.tyrus.TyrusServletWriter");
177-
Class<?> listenerType = loader.loadClass("weblogic.websocket.tyrus.TyrusServletWriter$CloseListener");
178-
Class<?> webSocketType = TyrusMuxableWebSocketHelper.webSocketType;
270+
Class<?> writerType = type("weblogic.websocket.tyrus.TyrusServletWriter");
271+
Class<?> listenerType = type("weblogic.websocket.tyrus.TyrusServletWriter$CloseListener");
272+
Class<?> webSocketType = TyrusMuxableWebSocketHelper.type;
179273
Class<HttpServletResponse> responseType = HttpServletResponse.class;
180-
constructor = type.getDeclaredConstructor(webSocketType, responseType, listenerType, boolean.class);
274+
275+
Class<?>[] argTypes = (WLS_12_1_3 ?
276+
new Class<?>[] {webSocketType, responseType, listenerType, boolean.class} :
277+
new Class<?>[] {webSocketType, listenerType, boolean.class});
278+
279+
constructor = writerType.getDeclaredConstructor(argTypes);
181280
ReflectionUtils.makeAccessible(constructor);
182281
}
183282
catch (Exception ex) {
@@ -187,7 +286,11 @@ private static class WebLogicServletWriterHelper {
187286

188287
private Writer newInstance(HttpServletResponse response, Object webSocket, boolean isProtected) {
189288
try {
190-
return (Writer) constructor.newInstance(webSocket, response, null, isProtected);
289+
Object[] args = (WLS_12_1_3 ?
290+
new Object[] {webSocket, response, null, isProtected} :
291+
new Object[] {webSocket, null, isProtected});
292+
293+
return (Writer) constructor.newInstance(args);
191294
}
192295
catch (Exception ex) {
193296
throw new HandshakeFailureException("Failed to create TyrusServletWriter", ex);

0 commit comments

Comments
 (0)