30
30
import javax .servlet .http .HttpServletResponse ;
31
31
import javax .websocket .CloseReason ;
32
32
33
+ import org .glassfish .tyrus .core .TyrusEndpointWrapper ;
33
34
import org .glassfish .tyrus .core .TyrusUpgradeResponse ;
35
+ import org .glassfish .tyrus .core .TyrusWebSocketEngine ;
34
36
import org .glassfish .tyrus .core .Utils ;
35
37
import org .glassfish .tyrus .spi .Connection ;
36
38
import org .glassfish .tyrus .spi .WebSocketEngine .UpgradeInfo ;
37
39
import org .glassfish .tyrus .spi .Writer ;
38
40
39
41
import org .springframework .beans .BeanWrapper ;
40
42
import org .springframework .beans .BeanWrapperImpl ;
43
+ import org .springframework .util .ClassUtils ;
41
44
import org .springframework .util .ReflectionUtils ;
42
45
import org .springframework .web .socket .server .HandshakeFailureException ;
43
46
44
47
/**
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.
46
50
*
47
51
* @author Rossen Stoyanchev
48
52
* @since 4.1
49
53
*/
50
54
public class WebLogicRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeStrategy {
51
55
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 ();
53
62
54
63
private static final TyrusMuxableWebSocketHelper webSocketHelper = new TyrusMuxableWebSocketHelper ();
55
64
56
65
private static final WebLogicServletWriterHelper servletWriterHelper = new WebLogicServletWriterHelper ();
57
66
58
67
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
+
59
84
@ Override
60
85
protected TyrusEndpointHelper getEndpointHelper () {
61
86
return endpointHelper ;
@@ -76,7 +101,7 @@ protected void handleSuccess(HttpServletRequest request, HttpServletResponse res
76
101
Object nativeRequest = getNativeRequest (request );
77
102
BeanWrapper beanWrapper = new BeanWrapperImpl (nativeRequest );
78
103
Object httpSocket = beanWrapper .getPropertyValue ("connection.connectionHandler.rawConnection" );
79
- Object webSocket = webSocketHelper .newInstance (httpSocket );
104
+ Object webSocket = webSocketHelper .newInstance (request , httpSocket );
80
105
webSocketHelper .upgrade (webSocket , httpSocket , request .getServletContext ());
81
106
82
107
response .flushBuffer ();
@@ -96,6 +121,16 @@ private static Object getNativeRequest(ServletRequest request) {
96
121
return request ;
97
122
}
98
123
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
+
99
134
100
135
private static final Connection .CloseListener noOpCloseListener = new Connection .CloseListener () {
101
136
@@ -110,33 +145,47 @@ public void close(CloseReason reason) {
110
145
*/
111
146
private static class TyrusMuxableWebSocketHelper {
112
147
113
- public static final Class <?> webSocketType ;
148
+ private static final Class <?> type ;
149
+
150
+ private static final Constructor <?> constructor ;
114
151
115
- private static final Constructor <?> webSocketConstructor ;
152
+ private static final SubjectHelper subjectHelper ;
116
153
117
- private static final Method webSocketUpgradeMethod ;
154
+ private static final Method upgradeMethod ;
118
155
119
- private static final Method webSocketReadEventMethod ;
156
+ private static final Method readEventMethod ;
120
157
121
158
static {
122
159
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" );
131
176
}
132
177
catch (Exception ex ) {
133
178
throw new IllegalStateException ("No compatible WebSocket version found" , ex );
134
179
}
135
180
}
136
181
137
- private Object newInstance (Object httpSocket ) {
182
+ private Object newInstance (HttpServletRequest request , Object httpSocket ) {
138
183
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 );
140
189
}
141
190
catch (Exception ex ) {
142
191
throw new HandshakeFailureException ("Failed to create TyrusMuxableWebSocket" , ex );
@@ -145,7 +194,7 @@ private Object newInstance(Object httpSocket) {
145
194
146
195
private void upgrade (Object webSocket , Object httpSocket , ServletContext servletContext ) {
147
196
try {
148
- webSocketUpgradeMethod .invoke (webSocket , httpSocket , servletContext );
197
+ upgradeMethod .invoke (webSocket , httpSocket , servletContext );
149
198
}
150
199
catch (Exception ex ) {
151
200
throw new HandshakeFailureException ("Failed to upgrade TyrusMuxableWebSocket" , ex );
@@ -154,14 +203,60 @@ private void upgrade(Object webSocket, Object httpSocket, ServletContext servlet
154
203
155
204
private void registerForReadEvent (Object webSocket ) {
156
205
try {
157
- webSocketReadEventMethod .invoke (webSocket );
206
+ readEventMethod .invoke (webSocket );
158
207
}
159
208
catch (Exception ex ) {
160
209
throw new HandshakeFailureException ("Failed to register WebSocket for read event" , ex );
161
210
}
162
211
}
163
212
}
164
213
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
+ }
165
260
166
261
/**
167
262
* Helps to create and invoke {@code weblogic.websocket.tyrus.TyrusServletWriter}.
@@ -172,12 +267,16 @@ private static class WebLogicServletWriterHelper {
172
267
173
268
static {
174
269
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 ;
179
273
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 );
181
280
ReflectionUtils .makeAccessible (constructor );
182
281
}
183
282
catch (Exception ex ) {
@@ -187,7 +286,11 @@ private static class WebLogicServletWriterHelper {
187
286
188
287
private Writer newInstance (HttpServletResponse response , Object webSocket , boolean isProtected ) {
189
288
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 );
191
294
}
192
295
catch (Exception ex ) {
193
296
throw new HandshakeFailureException ("Failed to create TyrusServletWriter" , ex );
0 commit comments