Require Undertow 1.3.5+, Tyrus 1.11+, Jetty 9.3+, Tomcat 8.5+
Issue: SPR-13495
This commit is contained in:
parent
ccf791b63f
commit
770f0c0661
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.catalina.loader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A mock of Tomcat's {@code WebappClassLoader} just for Spring's compilation purposes.
|
|
||||||
* Exposes both pre-7.0.63 as well as 7.0.63+ variants of {@code findResourceInternal}.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 4.2
|
|
||||||
*/
|
|
||||||
public class WebappClassLoader extends ClassLoader {
|
|
||||||
|
|
||||||
public WebappClassLoader() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebappClassLoader(ClassLoader parent) {
|
|
||||||
super(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected ResourceEntry findResourceInternal(String name, String path) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ResourceEntry findResourceInternal(String name, String path, boolean manifestRequired) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2007 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.instrument.classloading;
|
|
||||||
|
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
|
||||||
import java.lang.instrument.IllegalClassFormatException;
|
|
||||||
import java.security.ProtectionDomain;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ClassFileTransformer-based weaver, allowing for a list of transformers to be
|
|
||||||
* applied on a class byte array. Normally used inside class loaders.
|
|
||||||
*
|
|
||||||
* <p>Note: This class is deliberately implemented for minimal external dependencies,
|
|
||||||
* since it is included in weaver jars (to be deployed into application servers).
|
|
||||||
*
|
|
||||||
* @author Rod Johnson
|
|
||||||
* @author Costin Leau
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
public class WeavingTransformer {
|
|
||||||
|
|
||||||
private final ClassLoader classLoader;
|
|
||||||
|
|
||||||
private final List<ClassFileTransformer> transformers = new ArrayList<ClassFileTransformer>();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new WeavingTransformer for the given class loader.
|
|
||||||
* @param classLoader the ClassLoader to build a transformer for
|
|
||||||
*/
|
|
||||||
public WeavingTransformer(ClassLoader classLoader) {
|
|
||||||
if (classLoader == null) {
|
|
||||||
throw new IllegalArgumentException("ClassLoader must not be null");
|
|
||||||
}
|
|
||||||
this.classLoader = classLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a class file transformer to be applied by this weaver.
|
|
||||||
* @param transformer the class file transformer to register
|
|
||||||
*/
|
|
||||||
public void addTransformer(ClassFileTransformer transformer) {
|
|
||||||
if (transformer == null) {
|
|
||||||
throw new IllegalArgumentException("Transformer must not be null");
|
|
||||||
}
|
|
||||||
this.transformers.add(transformer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply transformation on a given class byte definition.
|
|
||||||
* The method will always return a non-null byte array (if no transformation has taken place
|
|
||||||
* the array content will be identical to the original one).
|
|
||||||
* @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass)
|
|
||||||
* @param bytes class byte definition
|
|
||||||
* @return (possibly transformed) class byte definition
|
|
||||||
*/
|
|
||||||
public byte[] transformIfNecessary(String className, byte[] bytes) {
|
|
||||||
String internalName = className.replace(".", "/");
|
|
||||||
return transformIfNecessary(className, internalName, bytes, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply transformation on a given class byte definition.
|
|
||||||
* The method will always return a non-null byte array (if no transformation has taken place
|
|
||||||
* the array content will be identical to the original one).
|
|
||||||
* @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass)
|
|
||||||
* @param internalName class name internal name in / format (i.e. some/package/SomeClass)
|
|
||||||
* @param bytes class byte definition
|
|
||||||
* @param pd protection domain to be used (can be null)
|
|
||||||
* @return (possibly transformed) class byte definition
|
|
||||||
*/
|
|
||||||
public byte[] transformIfNecessary(String className, String internalName, byte[] bytes, ProtectionDomain pd) {
|
|
||||||
byte[] result = bytes;
|
|
||||||
for (ClassFileTransformer cft : this.transformers) {
|
|
||||||
try {
|
|
||||||
byte[] transformed = cft.transform(this.classLoader, internalName, null, pd, result);
|
|
||||||
if (transformed != null) {
|
|
||||||
result = transformed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IllegalClassFormatException ex) {
|
|
||||||
throw new IllegalStateException("Class file transformation failed", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2015 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.instrument.classloading.tomcat;
|
|
||||||
|
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
|
|
||||||
import org.apache.catalina.loader.ResourceEntry;
|
|
||||||
import org.apache.catalina.loader.WebappClassLoader;
|
|
||||||
|
|
||||||
import org.springframework.instrument.classloading.WeavingTransformer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension of Tomcat's default class loader which adds instrumentation
|
|
||||||
* to loaded classes without the need to use a VM-wide agent.
|
|
||||||
*
|
|
||||||
* <p>To be registered using a
|
|
||||||
* <a href="http://tomcat.apache.org/tomcat-6.0-doc/config/loader.html">{@code Loader}</a> tag
|
|
||||||
* in Tomcat's <a href="http://tomcat.apache.org/tomcat-6.0-doc/config/context.html">{@code Context}</a>
|
|
||||||
* definition in the {@code server.xml} file, with the Spring-provided "spring-instrument-tomcat.jar"
|
|
||||||
* file deployed into Tomcat's "lib" directory. The required configuration tag looks as follows:
|
|
||||||
*
|
|
||||||
* <pre class="code"><Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/></pre>
|
|
||||||
*
|
|
||||||
* <p>Typically used in combination with a
|
|
||||||
* {@link org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver}
|
|
||||||
* defined in the Spring application context. The {@code addTransformer} and
|
|
||||||
* {@code getThrowawayClassLoader} methods mirror the corresponding methods
|
|
||||||
* in the LoadTimeWeaver interface, as expected by ReflectiveLoadTimeWeaver.
|
|
||||||
*
|
|
||||||
* <p><b>NOTE:</b> Requires Apache Tomcat version 6.0 or higher, as of Spring 4.0.
|
|
||||||
* This class is not intended to work on Tomcat 8.0+; please rely on Tomcat's own
|
|
||||||
* {@code InstrumentableClassLoader} facility instead, as autodetected by Spring's
|
|
||||||
* {@link org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver}.
|
|
||||||
*
|
|
||||||
* @author Costin Leau
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 2.0
|
|
||||||
* @see #addTransformer
|
|
||||||
* @see #getThrowawayClassLoader
|
|
||||||
* @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
|
|
||||||
* @see org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver
|
|
||||||
*/
|
|
||||||
public class TomcatInstrumentableClassLoader extends WebappClassLoader {
|
|
||||||
|
|
||||||
private static final String CLASS_SUFFIX = ".class";
|
|
||||||
|
|
||||||
/** Use an internal WeavingTransformer */
|
|
||||||
private final WeavingTransformer weavingTransformer;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@code TomcatInstrumentableClassLoader} using the
|
|
||||||
* current context class loader.
|
|
||||||
* @see #TomcatInstrumentableClassLoader(ClassLoader)
|
|
||||||
*/
|
|
||||||
public TomcatInstrumentableClassLoader() {
|
|
||||||
super();
|
|
||||||
this.weavingTransformer = new WeavingTransformer(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@code TomcatInstrumentableClassLoader} with the
|
|
||||||
* supplied class loader as parent.
|
|
||||||
* @param parent the parent {@link ClassLoader} to be used
|
|
||||||
*/
|
|
||||||
public TomcatInstrumentableClassLoader(ClassLoader parent) {
|
|
||||||
super(parent);
|
|
||||||
this.weavingTransformer = new WeavingTransformer(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delegate for LoadTimeWeaver's {@code addTransformer} method.
|
|
||||||
* Typically called through ReflectiveLoadTimeWeaver.
|
|
||||||
* @see org.springframework.instrument.classloading.LoadTimeWeaver#addTransformer
|
|
||||||
* @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
|
|
||||||
*/
|
|
||||||
public void addTransformer(ClassFileTransformer transformer) {
|
|
||||||
this.weavingTransformer.addTransformer(transformer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delegate for LoadTimeWeaver's {@code getThrowawayClassLoader} method.
|
|
||||||
* Typically called through ReflectiveLoadTimeWeaver.
|
|
||||||
* @see org.springframework.instrument.classloading.LoadTimeWeaver#getThrowawayClassLoader
|
|
||||||
* @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
|
|
||||||
*/
|
|
||||||
public ClassLoader getThrowawayClassLoader() {
|
|
||||||
WebappClassLoader tempLoader = new WebappClassLoader();
|
|
||||||
// Use reflection to copy all the fields since they are not exposed any other way.
|
|
||||||
shallowCopyFieldState(this, tempLoader);
|
|
||||||
return tempLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override // overriding the pre-7.0.63 variant of findResourceInternal
|
|
||||||
protected ResourceEntry findResourceInternal(String name, String path) {
|
|
||||||
ResourceEntry entry = super.findResourceInternal(name, path);
|
|
||||||
if (entry != null && entry.binaryContent != null && path.endsWith(CLASS_SUFFIX)) {
|
|
||||||
String className = (name.endsWith(CLASS_SUFFIX) ? name.substring(0, name.length() - CLASS_SUFFIX.length()) : name);
|
|
||||||
entry.binaryContent = this.weavingTransformer.transformIfNecessary(className, entry.binaryContent);
|
|
||||||
}
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override // overriding the 7.0.63+ variant of findResourceInternal
|
|
||||||
protected ResourceEntry findResourceInternal(String name, String path, boolean manifestRequired) {
|
|
||||||
ResourceEntry entry = super.findResourceInternal(name, path, manifestRequired);
|
|
||||||
if (entry != null && entry.binaryContent != null && path.endsWith(CLASS_SUFFIX)) {
|
|
||||||
String className = (name.endsWith(CLASS_SUFFIX) ? name.substring(0, name.length() - CLASS_SUFFIX.length()) : name);
|
|
||||||
entry.binaryContent = this.weavingTransformer.transformIfNecessary(className, entry.binaryContent);
|
|
||||||
}
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getClass().getName() + "\r\n" + super.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// The code below is originally taken from ReflectionUtils and optimized for
|
|
||||||
// local usage. There is no dependency on ReflectionUtils to keep this class
|
|
||||||
// self-contained (since it gets deployed into Tomcat's server class loader).
|
|
||||||
private static void shallowCopyFieldState(final WebappClassLoader src, final WebappClassLoader dest) {
|
|
||||||
Class<?> targetClass = WebappClassLoader.class;
|
|
||||||
// Keep backing up the inheritance hierarchy.
|
|
||||||
do {
|
|
||||||
Field[] fields = targetClass.getDeclaredFields();
|
|
||||||
for (Field field : fields) {
|
|
||||||
// Do not copy resourceEntries - it's a cache that holds class entries.
|
|
||||||
if (!(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()) ||
|
|
||||||
field.getName().equals("resourceEntries"))) {
|
|
||||||
try {
|
|
||||||
field.setAccessible(true);
|
|
||||||
Object srcValue = field.get(src);
|
|
||||||
field.set(dest, srcValue);
|
|
||||||
}
|
|
||||||
catch (IllegalAccessException ex) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Shouldn't be illegal to access field '" + field.getName() + "': " + ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
targetClass = targetClass.getSuperclass();
|
|
||||||
}
|
|
||||||
while (targetClass != null && targetClass != Object.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
<p>
|
|
||||||
Spring's instrumentation agent for Tomcat.
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
|
||||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
|
||||||
log4j.appender.console.layout.ConversionPattern=%d{HH:mm:ss,SSS} [%c] - %m%n
|
|
||||||
|
|
||||||
log4j.rootCategory=WARN, console
|
|
||||||
log4j.logger.org.springframework.beans=WARN
|
|
||||||
log4j.logger.org.springframework.binding=DEBUG
|
|
||||||
|
|
||||||
#log4j.logger.org.springframework.instrument.classloading=TRACE
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -56,8 +56,8 @@ import org.springframework.web.socket.server.HandshakeFailureException;
|
||||||
import org.springframework.web.socket.server.RequestUpgradeStrategy;
|
import org.springframework.web.socket.server.RequestUpgradeStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link RequestUpgradeStrategy} for use with Jetty 9.0-9.3. Based on Jetty's
|
* A {@link RequestUpgradeStrategy} for use with Jetty 9.3 and higher. Based on
|
||||||
* internal {@code org.eclipse.jetty.websocket.server.WebSocketHandler} class.
|
* Jetty's internal {@code org.eclipse.jetty.websocket.server.WebSocketHandler} class.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
|
@ -65,10 +65,6 @@ import org.springframework.web.socket.server.RequestUpgradeStrategy;
|
||||||
*/
|
*/
|
||||||
public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Lifecycle, ServletContextAware {
|
public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Lifecycle, ServletContextAware {
|
||||||
|
|
||||||
// Pre-Jetty 9.3 init method without ServletContext
|
|
||||||
private static final Method webSocketFactoryInitMethod =
|
|
||||||
ClassUtils.getMethodIfAvailable(WebSocketServerFactory.class, "init");
|
|
||||||
|
|
||||||
private static final ThreadLocal<WebSocketHandlerContainer> wsContainerHolder =
|
private static final ThreadLocal<WebSocketHandlerContainer> wsContainerHolder =
|
||||||
new NamedThreadLocal<WebSocketHandlerContainer>("WebSocket Handler Container");
|
new NamedThreadLocal<WebSocketHandlerContainer>("WebSocket Handler Container");
|
||||||
|
|
||||||
|
|
@ -153,13 +149,8 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life
|
||||||
if (!isRunning()) {
|
if (!isRunning()) {
|
||||||
this.running = true;
|
this.running = true;
|
||||||
try {
|
try {
|
||||||
if (webSocketFactoryInitMethod != null) {
|
|
||||||
webSocketFactoryInitMethod.invoke(this.factory);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.factory.init(this.servletContext);
|
this.factory.init(this.servletContext);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new IllegalStateException("Unable to initialize Jetty WebSocketServerFactory", ex);
|
throw new IllegalStateException("Unable to initialize Jetty WebSocketServerFactory", ex);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -35,12 +35,10 @@ import javax.websocket.WebSocketContainer;
|
||||||
|
|
||||||
import org.glassfish.tyrus.core.ComponentProviderService;
|
import org.glassfish.tyrus.core.ComponentProviderService;
|
||||||
import org.glassfish.tyrus.core.RequestContext;
|
import org.glassfish.tyrus.core.RequestContext;
|
||||||
import org.glassfish.tyrus.core.TyrusEndpoint;
|
|
||||||
import org.glassfish.tyrus.core.TyrusEndpointWrapper;
|
import org.glassfish.tyrus.core.TyrusEndpointWrapper;
|
||||||
import org.glassfish.tyrus.core.TyrusUpgradeResponse;
|
import org.glassfish.tyrus.core.TyrusUpgradeResponse;
|
||||||
import org.glassfish.tyrus.core.TyrusWebSocketEngine;
|
import org.glassfish.tyrus.core.TyrusWebSocketEngine;
|
||||||
import org.glassfish.tyrus.core.Version;
|
import org.glassfish.tyrus.core.Version;
|
||||||
import org.glassfish.tyrus.core.WebSocketApplication;
|
|
||||||
import org.glassfish.tyrus.server.TyrusServerContainer;
|
import org.glassfish.tyrus.server.TyrusServerContainer;
|
||||||
import org.glassfish.tyrus.spi.WebSocketEngine.UpgradeInfo;
|
import org.glassfish.tyrus.spi.WebSocketEngine.UpgradeInfo;
|
||||||
|
|
||||||
|
|
@ -59,11 +57,11 @@ import static org.glassfish.tyrus.spi.WebSocketEngine.UpgradeStatus.*;
|
||||||
* A base class for {@code RequestUpgradeStrategy} implementations on top of
|
* A base class for {@code RequestUpgradeStrategy} implementations on top of
|
||||||
* JSR-356 based servers which include Tyrus as their WebSocket engine.
|
* JSR-356 based servers which include Tyrus as their WebSocket engine.
|
||||||
*
|
*
|
||||||
* <p>Works with Tyrus 1.3.5 (WebLogic 12.1.3), Tyrus 1.7 (GlassFish 4.1.0),
|
* <p>Works with Tyrus 1.11 (WebLogic 12.2.1) and Tyrus 1.12 (GlassFish 4.1.1).
|
||||||
* Tyrus 1.11 (WebLogic 12.2.1), and Tyrus 1.12 (GlassFish 4.1.1).
|
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
* @see <a href="https://tyrus.java.net/">Project Tyrus</a>
|
* @see <a href="https://tyrus.java.net/">Project Tyrus</a>
|
||||||
*/
|
*/
|
||||||
|
|
@ -71,122 +69,6 @@ public abstract class AbstractTyrusRequestUpgradeStrategy extends AbstractStanda
|
||||||
|
|
||||||
private static final Random random = new Random();
|
private static final Random random = new Random();
|
||||||
|
|
||||||
private final ComponentProviderService componentProvider = ComponentProviderService.create();
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getSupportedVersions() {
|
|
||||||
return StringUtils.commaDelimitedListToStringArray(Version.getSupportedWireProtocolVersions());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<WebSocketExtension> getInstalledExtensions(WebSocketContainer container) {
|
|
||||||
try {
|
|
||||||
return super.getInstalledExtensions(container);
|
|
||||||
}
|
|
||||||
catch (UnsupportedOperationException ex) {
|
|
||||||
return new ArrayList<WebSocketExtension>(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void upgradeInternal(ServerHttpRequest request, ServerHttpResponse response,
|
|
||||||
String selectedProtocol, List<Extension> extensions, Endpoint endpoint)
|
|
||||||
throws HandshakeFailureException {
|
|
||||||
|
|
||||||
HttpServletRequest servletRequest = getHttpServletRequest(request);
|
|
||||||
HttpServletResponse servletResponse = getHttpServletResponse(response);
|
|
||||||
|
|
||||||
TyrusServerContainer serverContainer = (TyrusServerContainer) getContainer(servletRequest);
|
|
||||||
TyrusWebSocketEngine engine = (TyrusWebSocketEngine) serverContainer.getWebSocketEngine();
|
|
||||||
Object tyrusEndpoint = null;
|
|
||||||
boolean success;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Shouldn't matter for processing but must be unique
|
|
||||||
String path = "/" + random.nextLong();
|
|
||||||
tyrusEndpoint = createTyrusEndpoint(endpoint, path, selectedProtocol, extensions, serverContainer, engine);
|
|
||||||
getEndpointHelper().register(engine, tyrusEndpoint);
|
|
||||||
|
|
||||||
HttpHeaders headers = request.getHeaders();
|
|
||||||
RequestContext requestContext = createRequestContext(servletRequest, path, headers);
|
|
||||||
TyrusUpgradeResponse upgradeResponse = new TyrusUpgradeResponse();
|
|
||||||
UpgradeInfo upgradeInfo = engine.upgrade(requestContext, upgradeResponse);
|
|
||||||
success = SUCCESS.equals(upgradeInfo.getStatus());
|
|
||||||
if (success) {
|
|
||||||
if (logger.isTraceEnabled()) {
|
|
||||||
logger.trace("Successful request upgrade: " + upgradeResponse.getHeaders());
|
|
||||||
}
|
|
||||||
handleSuccess(servletRequest, servletResponse, upgradeInfo, upgradeResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
unregisterTyrusEndpoint(engine, tyrusEndpoint);
|
|
||||||
throw new HandshakeFailureException("Error during handshake: " + request.getURI(), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
unregisterTyrusEndpoint(engine, tyrusEndpoint);
|
|
||||||
if (!success) {
|
|
||||||
throw new HandshakeFailureException("Unexpected handshake failure: " + request.getURI());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object createTyrusEndpoint(Endpoint endpoint, String endpointPath, String protocol,
|
|
||||||
List<Extension> extensions, WebSocketContainer container, TyrusWebSocketEngine engine)
|
|
||||||
throws DeploymentException {
|
|
||||||
|
|
||||||
ServerEndpointRegistration endpointConfig = new ServerEndpointRegistration(endpointPath, endpoint);
|
|
||||||
endpointConfig.setSubprotocols(Collections.singletonList(protocol));
|
|
||||||
endpointConfig.setExtensions(extensions);
|
|
||||||
return getEndpointHelper().createdEndpoint(endpointConfig, this.componentProvider, container, engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
private RequestContext createRequestContext(HttpServletRequest request, String endpointPath, HttpHeaders headers) {
|
|
||||||
RequestContext context =
|
|
||||||
RequestContext.Builder.create()
|
|
||||||
.requestURI(URI.create(endpointPath))
|
|
||||||
.userPrincipal(request.getUserPrincipal())
|
|
||||||
.secure(request.isSecure())
|
|
||||||
// .remoteAddr(request.getRemoteAddr()) # Not available in 1.3.5
|
|
||||||
.build();
|
|
||||||
for (String header : headers.keySet()) {
|
|
||||||
context.getHeaders().put(header, headers.get(header));
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void unregisterTyrusEndpoint(TyrusWebSocketEngine engine, Object tyrusEndpoint) {
|
|
||||||
if (tyrusEndpoint != null) {
|
|
||||||
try {
|
|
||||||
getEndpointHelper().unregister(engine, tyrusEndpoint);
|
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract TyrusEndpointHelper getEndpointHelper();
|
|
||||||
|
|
||||||
protected abstract void handleSuccess(HttpServletRequest request, HttpServletResponse response,
|
|
||||||
UpgradeInfo upgradeInfo, TyrusUpgradeResponse upgradeResponse) throws IOException, ServletException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helps with the creation, registration, and un-registration of endpoints.
|
|
||||||
*/
|
|
||||||
protected interface TyrusEndpointHelper {
|
|
||||||
|
|
||||||
Object createdEndpoint(ServerEndpointRegistration registration, ComponentProviderService provider,
|
|
||||||
WebSocketContainer container, TyrusWebSocketEngine engine) throws DeploymentException;
|
|
||||||
|
|
||||||
void register(TyrusWebSocketEngine engine, Object endpoint);
|
|
||||||
|
|
||||||
void unregister(TyrusWebSocketEngine engine, Object endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected static class Tyrus17EndpointHelper implements TyrusEndpointHelper {
|
|
||||||
|
|
||||||
private static final Constructor<?> constructor;
|
private static final Constructor<?> constructor;
|
||||||
|
|
||||||
private static boolean constructorWithBooleanArgument;
|
private static boolean constructorWithBooleanArgument;
|
||||||
|
|
@ -223,8 +105,101 @@ public abstract class AbstractTyrusRequestUpgradeStrategy extends AbstractStanda
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private final ComponentProviderService componentProvider = ComponentProviderService.create();
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object createdEndpoint(ServerEndpointRegistration registration, ComponentProviderService provider,
|
public String[] getSupportedVersions() {
|
||||||
|
return StringUtils.commaDelimitedListToStringArray(Version.getSupportedWireProtocolVersions());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<WebSocketExtension> getInstalledExtensions(WebSocketContainer container) {
|
||||||
|
try {
|
||||||
|
return super.getInstalledExtensions(container);
|
||||||
|
}
|
||||||
|
catch (UnsupportedOperationException ex) {
|
||||||
|
return new ArrayList<WebSocketExtension>(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void upgradeInternal(ServerHttpRequest request, ServerHttpResponse response,
|
||||||
|
String selectedProtocol, List<Extension> extensions, Endpoint endpoint)
|
||||||
|
throws HandshakeFailureException {
|
||||||
|
|
||||||
|
HttpServletRequest servletRequest = getHttpServletRequest(request);
|
||||||
|
HttpServletResponse servletResponse = getHttpServletResponse(response);
|
||||||
|
|
||||||
|
TyrusServerContainer serverContainer = (TyrusServerContainer) getContainer(servletRequest);
|
||||||
|
TyrusWebSocketEngine engine = (TyrusWebSocketEngine) serverContainer.getWebSocketEngine();
|
||||||
|
Object tyrusEndpoint = null;
|
||||||
|
boolean success;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Shouldn't matter for processing but must be unique
|
||||||
|
String path = "/" + random.nextLong();
|
||||||
|
tyrusEndpoint = createTyrusEndpoint(endpoint, path, selectedProtocol, extensions, serverContainer, engine);
|
||||||
|
register(engine, tyrusEndpoint);
|
||||||
|
|
||||||
|
HttpHeaders headers = request.getHeaders();
|
||||||
|
RequestContext requestContext = createRequestContext(servletRequest, path, headers);
|
||||||
|
TyrusUpgradeResponse upgradeResponse = new TyrusUpgradeResponse();
|
||||||
|
UpgradeInfo upgradeInfo = engine.upgrade(requestContext, upgradeResponse);
|
||||||
|
success = SUCCESS.equals(upgradeInfo.getStatus());
|
||||||
|
if (success) {
|
||||||
|
if (logger.isTraceEnabled()) {
|
||||||
|
logger.trace("Successful request upgrade: " + upgradeResponse.getHeaders());
|
||||||
|
}
|
||||||
|
handleSuccess(servletRequest, servletResponse, upgradeInfo, upgradeResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
unregisterTyrusEndpoint(engine, tyrusEndpoint);
|
||||||
|
throw new HandshakeFailureException("Error during handshake: " + request.getURI(), ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
unregisterTyrusEndpoint(engine, tyrusEndpoint);
|
||||||
|
if (!success) {
|
||||||
|
throw new HandshakeFailureException("Unexpected handshake failure: " + request.getURI());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object createTyrusEndpoint(Endpoint endpoint, String endpointPath, String protocol,
|
||||||
|
List<Extension> extensions, WebSocketContainer container, TyrusWebSocketEngine engine)
|
||||||
|
throws DeploymentException {
|
||||||
|
|
||||||
|
ServerEndpointRegistration endpointConfig = new ServerEndpointRegistration(endpointPath, endpoint);
|
||||||
|
endpointConfig.setSubprotocols(Collections.singletonList(protocol));
|
||||||
|
endpointConfig.setExtensions(extensions);
|
||||||
|
return createEndpoint(endpointConfig, this.componentProvider, container, engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RequestContext createRequestContext(HttpServletRequest request, String endpointPath, HttpHeaders headers) {
|
||||||
|
RequestContext context =
|
||||||
|
RequestContext.Builder.create()
|
||||||
|
.requestURI(URI.create(endpointPath))
|
||||||
|
.userPrincipal(request.getUserPrincipal())
|
||||||
|
.secure(request.isSecure())
|
||||||
|
.remoteAddr(request.getRemoteAddr())
|
||||||
|
.build();
|
||||||
|
for (String header : headers.keySet()) {
|
||||||
|
context.getHeaders().put(header, headers.get(header));
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregisterTyrusEndpoint(TyrusWebSocketEngine engine, Object tyrusEndpoint) {
|
||||||
|
if (tyrusEndpoint != null) {
|
||||||
|
try {
|
||||||
|
unregister(engine, tyrusEndpoint);
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object createEndpoint(ServerEndpointRegistration registration, ComponentProviderService provider,
|
||||||
WebSocketContainer container, TyrusWebSocketEngine engine) throws DeploymentException {
|
WebSocketContainer container, TyrusWebSocketEngine engine) throws DeploymentException {
|
||||||
|
|
||||||
DirectFieldAccessor accessor = new DirectFieldAccessor(engine);
|
DirectFieldAccessor accessor = new DirectFieldAccessor(engine);
|
||||||
|
|
@ -246,8 +221,7 @@ public abstract class AbstractTyrusRequestUpgradeStrategy extends AbstractStanda
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void register(TyrusWebSocketEngine engine, Object endpoint) {
|
||||||
public void register(TyrusWebSocketEngine engine, Object endpoint) {
|
|
||||||
try {
|
try {
|
||||||
registerMethod.invoke(engine, endpoint);
|
registerMethod.invoke(engine, endpoint);
|
||||||
}
|
}
|
||||||
|
|
@ -256,8 +230,7 @@ public abstract class AbstractTyrusRequestUpgradeStrategy extends AbstractStanda
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void unregister(TyrusWebSocketEngine engine, Object endpoint) {
|
||||||
public void unregister(TyrusWebSocketEngine engine, Object endpoint) {
|
|
||||||
try {
|
try {
|
||||||
unRegisterMethod.invoke(engine, endpoint);
|
unRegisterMethod.invoke(engine, endpoint);
|
||||||
}
|
}
|
||||||
|
|
@ -265,47 +238,9 @@ public abstract class AbstractTyrusRequestUpgradeStrategy extends AbstractStanda
|
||||||
throw new HandshakeFailureException("Failed to unregister " + endpoint, ex);
|
throw new HandshakeFailureException("Failed to unregister " + endpoint, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected static class Tyrus135EndpointHelper implements TyrusEndpointHelper {
|
protected abstract void handleSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
UpgradeInfo upgradeInfo, TyrusUpgradeResponse upgradeResponse) throws IOException, ServletException;
|
||||||
private static final Method registerMethod;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
registerMethod = TyrusWebSocketEngine.class.getDeclaredMethod("register", WebSocketApplication.class);
|
|
||||||
ReflectionUtils.makeAccessible(registerMethod);
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new IllegalStateException("No compatible Tyrus version found", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object createdEndpoint(ServerEndpointRegistration registration, ComponentProviderService provider,
|
|
||||||
WebSocketContainer container, TyrusWebSocketEngine engine) throws DeploymentException {
|
|
||||||
|
|
||||||
TyrusEndpointWrapper endpointWrapper = new TyrusEndpointWrapper(registration.getEndpoint(),
|
|
||||||
registration, provider, container, "/", registration.getConfigurator());
|
|
||||||
|
|
||||||
return new TyrusEndpoint(endpointWrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void register(TyrusWebSocketEngine engine, Object endpoint) {
|
|
||||||
try {
|
|
||||||
registerMethod.invoke(engine, endpoint);
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new HandshakeFailureException("Failed to register " + endpoint, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unregister(TyrusWebSocketEngine engine, Object endpoint) {
|
|
||||||
engine.unregister((TyrusEndpoint) endpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -43,37 +43,6 @@ import org.springframework.web.socket.server.HandshakeFailureException;
|
||||||
*/
|
*/
|
||||||
public class GlassFishRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeStrategy {
|
public class GlassFishRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeStrategy {
|
||||||
|
|
||||||
private static final TyrusEndpointHelper endpointHelper = new Tyrus17EndpointHelper();
|
|
||||||
|
|
||||||
private static final GlassFishServletWriterHelper servletWriterHelper = new GlassFishServletWriterHelper();
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected TyrusEndpointHelper getEndpointHelper() {
|
|
||||||
return endpointHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void handleSuccess(HttpServletRequest request, HttpServletResponse response,
|
|
||||||
UpgradeInfo upgradeInfo, TyrusUpgradeResponse upgradeResponse) throws IOException, ServletException {
|
|
||||||
|
|
||||||
TyrusHttpUpgradeHandler handler = request.upgrade(TyrusHttpUpgradeHandler.class);
|
|
||||||
Writer servletWriter = servletWriterHelper.newInstance(handler);
|
|
||||||
handler.preInit(upgradeInfo, servletWriter, request.getUserPrincipal() != null);
|
|
||||||
|
|
||||||
response.setStatus(upgradeResponse.getStatus());
|
|
||||||
for (Map.Entry<String, List<String>> entry : upgradeResponse.getHeaders().entrySet()) {
|
|
||||||
response.addHeader(entry.getKey(), Utils.getHeaderFromList(entry.getValue()));
|
|
||||||
}
|
|
||||||
response.flushBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helps to create and invoke {@code org.glassfish.tyrus.servlet.TyrusServletWriter}.
|
|
||||||
*/
|
|
||||||
private static class GlassFishServletWriterHelper {
|
|
||||||
|
|
||||||
private static final Constructor<?> constructor;
|
private static final Constructor<?> constructor;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
@ -88,7 +57,23 @@ public class GlassFishRequestUpgradeStrategy extends AbstractTyrusRequestUpgrade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Writer newInstance(TyrusHttpUpgradeHandler handler) {
|
|
||||||
|
@Override
|
||||||
|
protected void handleSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
UpgradeInfo upgradeInfo, TyrusUpgradeResponse upgradeResponse) throws IOException, ServletException {
|
||||||
|
|
||||||
|
TyrusHttpUpgradeHandler handler = request.upgrade(TyrusHttpUpgradeHandler.class);
|
||||||
|
Writer servletWriter = newServletWriter(handler);
|
||||||
|
handler.preInit(upgradeInfo, servletWriter, request.getUserPrincipal() != null);
|
||||||
|
|
||||||
|
response.setStatus(upgradeResponse.getStatus());
|
||||||
|
for (Map.Entry<String, List<String>> entry : upgradeResponse.getHeaders().entrySet()) {
|
||||||
|
response.addHeader(entry.getKey(), Utils.getHeaderFromList(entry.getValue()));
|
||||||
|
}
|
||||||
|
response.flushBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Writer newServletWriter(TyrusHttpUpgradeHandler handler) {
|
||||||
try {
|
try {
|
||||||
return (Writer) constructor.newInstance(handler);
|
return (Writer) constructor.newInstance(handler);
|
||||||
}
|
}
|
||||||
|
|
@ -96,6 +81,5 @@ public class GlassFishRequestUpgradeStrategy extends AbstractTyrusRequestUpgrade
|
||||||
throw new HandshakeFailureException("Failed to instantiate TyrusServletWriter", ex);
|
throw new HandshakeFailureException("Failed to instantiate TyrusServletWriter", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -17,66 +17,33 @@
|
||||||
package org.springframework.web.socket.server.standard;
|
package org.springframework.web.socket.server.standard;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.websocket.Decoder;
|
|
||||||
import javax.websocket.Encoder;
|
|
||||||
import javax.websocket.Endpoint;
|
import javax.websocket.Endpoint;
|
||||||
import javax.websocket.Extension;
|
import javax.websocket.Extension;
|
||||||
import javax.websocket.server.ServerEndpointConfig;
|
|
||||||
|
|
||||||
import io.undertow.server.HttpServerExchange;
|
|
||||||
import io.undertow.server.HttpUpgradeListener;
|
|
||||||
import io.undertow.servlet.api.InstanceFactory;
|
|
||||||
import io.undertow.servlet.api.InstanceHandle;
|
|
||||||
import io.undertow.servlet.websockets.ServletWebSocketHttpExchange;
|
|
||||||
import io.undertow.util.PathTemplate;
|
|
||||||
import io.undertow.websockets.core.WebSocketChannel;
|
|
||||||
import io.undertow.websockets.core.WebSocketVersion;
|
import io.undertow.websockets.core.WebSocketVersion;
|
||||||
import io.undertow.websockets.core.protocol.Handshake;
|
|
||||||
import io.undertow.websockets.jsr.ConfiguredServerEndpoint;
|
|
||||||
import io.undertow.websockets.jsr.EncodingFactory;
|
|
||||||
import io.undertow.websockets.jsr.EndpointSessionHandler;
|
|
||||||
import io.undertow.websockets.jsr.ServerWebSocketContainer;
|
import io.undertow.websockets.jsr.ServerWebSocketContainer;
|
||||||
import io.undertow.websockets.jsr.annotated.AnnotatedEndpointFactory;
|
|
||||||
import io.undertow.websockets.jsr.handshake.HandshakeUtil;
|
|
||||||
import io.undertow.websockets.jsr.handshake.JsrHybi07Handshake;
|
|
||||||
import io.undertow.websockets.jsr.handshake.JsrHybi08Handshake;
|
|
||||||
import io.undertow.websockets.jsr.handshake.JsrHybi13Handshake;
|
|
||||||
import io.undertow.websockets.spi.WebSocketHttpExchange;
|
|
||||||
import org.xnio.StreamConnection;
|
|
||||||
|
|
||||||
import org.springframework.http.server.ServerHttpRequest;
|
import org.springframework.http.server.ServerHttpRequest;
|
||||||
import org.springframework.http.server.ServerHttpResponse;
|
import org.springframework.http.server.ServerHttpResponse;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
import org.springframework.web.socket.server.HandshakeFailureException;
|
import org.springframework.web.socket.server.HandshakeFailureException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A WebSocket {@code RequestUpgradeStrategy} for WildFly and its underlying
|
* A WebSocket {@code RequestUpgradeStrategy} for WildFly and its underlying
|
||||||
* Undertow web server. Also compatible with embedded Undertow usage.
|
* Undertow web server. Also compatible with embedded Undertow usage.
|
||||||
*
|
*
|
||||||
* <p>Designed for Undertow 1.3.5+ as of Spring Framework 4.3, with a fallback
|
* <p>Requires Undertow 1.3.5+ as of Spring Framework 5.0.
|
||||||
* strategy for Undertow 1.0 to 1.3 - as included in WildFly 8.x, 9 and 10.
|
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.0.1
|
* @since 4.0.1
|
||||||
*/
|
*/
|
||||||
public class UndertowRequestUpgradeStrategy extends AbstractStandardUpgradeStrategy {
|
public class UndertowRequestUpgradeStrategy extends AbstractStandardUpgradeStrategy {
|
||||||
|
|
||||||
private static final boolean HAS_DO_UPGRADE = ClassUtils.hasMethod(ServerWebSocketContainer.class, "doUpgrade",
|
|
||||||
HttpServletRequest.class, HttpServletResponse.class, ServerEndpointConfig.class, Map.class);
|
|
||||||
|
|
||||||
private static final FallbackStrategy FALLBACK_STRATEGY = (HAS_DO_UPGRADE ? null : new FallbackStrategy());
|
|
||||||
|
|
||||||
private static final String[] VERSIONS = new String[] {
|
private static final String[] VERSIONS = new String[] {
|
||||||
WebSocketVersion.V13.toHttpHeaderValue(),
|
WebSocketVersion.V13.toHttpHeaderValue(),
|
||||||
WebSocketVersion.V08.toHttpHeaderValue(),
|
WebSocketVersion.V08.toHttpHeaderValue(),
|
||||||
|
|
@ -94,7 +61,6 @@ public class UndertowRequestUpgradeStrategy extends AbstractStandardUpgradeStrat
|
||||||
String selectedProtocol, List<Extension> selectedExtensions, Endpoint endpoint)
|
String selectedProtocol, List<Extension> selectedExtensions, Endpoint endpoint)
|
||||||
throws HandshakeFailureException {
|
throws HandshakeFailureException {
|
||||||
|
|
||||||
if (HAS_DO_UPGRADE) {
|
|
||||||
HttpServletRequest servletRequest = getHttpServletRequest(request);
|
HttpServletRequest servletRequest = getHttpServletRequest(request);
|
||||||
HttpServletResponse servletResponse = getHttpServletResponse(response);
|
HttpServletResponse servletResponse = getHttpServletResponse(response);
|
||||||
|
|
||||||
|
|
@ -118,206 +84,9 @@ public class UndertowRequestUpgradeStrategy extends AbstractStandardUpgradeStrat
|
||||||
"Response update failed during upgrade to WebSocket: " + requestUrl, ex);
|
"Response update failed during upgrade to WebSocket: " + requestUrl, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
FALLBACK_STRATEGY.upgradeInternal(request, response, selectedProtocol, selectedExtensions, endpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerWebSocketContainer getContainer(HttpServletRequest request) {
|
public ServerWebSocketContainer getContainer(HttpServletRequest request) {
|
||||||
return (ServerWebSocketContainer) super.getContainer(request);
|
return (ServerWebSocketContainer) super.getContainer(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strategy for use with Undertow 1.0 to 1.3 before there was a public API
|
|
||||||
* to perform a WebSocket upgrade.
|
|
||||||
*/
|
|
||||||
private static class FallbackStrategy extends AbstractStandardUpgradeStrategy {
|
|
||||||
|
|
||||||
private static final Constructor<ServletWebSocketHttpExchange> exchangeConstructor;
|
|
||||||
|
|
||||||
private static final boolean exchangeConstructorWithPeerConnections;
|
|
||||||
|
|
||||||
private static final Constructor<ConfiguredServerEndpoint> endpointConstructor;
|
|
||||||
|
|
||||||
private static final boolean endpointConstructorWithEndpointFactory;
|
|
||||||
|
|
||||||
private static final Method getBufferPoolMethod;
|
|
||||||
|
|
||||||
private static final Method createChannelMethod;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
Class<ServletWebSocketHttpExchange> exchangeType = ServletWebSocketHttpExchange.class;
|
|
||||||
Class<?>[] exchangeParamTypes =
|
|
||||||
new Class<?>[] {HttpServletRequest.class, HttpServletResponse.class, Set.class};
|
|
||||||
Constructor<ServletWebSocketHttpExchange> exchangeCtor =
|
|
||||||
ClassUtils.getConstructorIfAvailable(exchangeType, exchangeParamTypes);
|
|
||||||
if (exchangeCtor != null) {
|
|
||||||
// Undertow 1.1+
|
|
||||||
exchangeConstructor = exchangeCtor;
|
|
||||||
exchangeConstructorWithPeerConnections = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Undertow 1.0
|
|
||||||
exchangeParamTypes = new Class<?>[] {HttpServletRequest.class, HttpServletResponse.class};
|
|
||||||
exchangeConstructor = exchangeType.getConstructor(exchangeParamTypes);
|
|
||||||
exchangeConstructorWithPeerConnections = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Class<ConfiguredServerEndpoint> endpointType = ConfiguredServerEndpoint.class;
|
|
||||||
Class<?>[] endpointParamTypes = new Class<?>[] {ServerEndpointConfig.class, InstanceFactory.class,
|
|
||||||
PathTemplate.class, EncodingFactory.class, AnnotatedEndpointFactory.class};
|
|
||||||
Constructor<ConfiguredServerEndpoint> endpointCtor =
|
|
||||||
ClassUtils.getConstructorIfAvailable(endpointType, endpointParamTypes);
|
|
||||||
if (endpointCtor != null) {
|
|
||||||
// Undertow 1.1+
|
|
||||||
endpointConstructor = endpointCtor;
|
|
||||||
endpointConstructorWithEndpointFactory = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Undertow 1.0
|
|
||||||
endpointParamTypes = new Class<?>[] {ServerEndpointConfig.class, InstanceFactory.class,
|
|
||||||
PathTemplate.class, EncodingFactory.class};
|
|
||||||
endpointConstructor = endpointType.getConstructor(endpointParamTypes);
|
|
||||||
endpointConstructorWithEndpointFactory = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adapting between different Pool API types in Undertow 1.0-1.2 vs 1.3
|
|
||||||
getBufferPoolMethod = WebSocketHttpExchange.class.getMethod("getBufferPool");
|
|
||||||
createChannelMethod = ReflectionUtils.findMethod(Handshake.class, "createChannel", (Class<?>[]) null);
|
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
throw new IllegalStateException("Incompatible Undertow API version", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Set<WebSocketChannel> peerConnections;
|
|
||||||
|
|
||||||
public FallbackStrategy() {
|
|
||||||
if (exchangeConstructorWithPeerConnections) {
|
|
||||||
this.peerConnections = Collections.newSetFromMap(new ConcurrentHashMap<WebSocketChannel, Boolean>());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.peerConnections = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getSupportedVersions() {
|
|
||||||
return VERSIONS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void upgradeInternal(ServerHttpRequest request, ServerHttpResponse response,
|
|
||||||
String selectedProtocol, List<Extension> selectedExtensions, final Endpoint endpoint)
|
|
||||||
throws HandshakeFailureException {
|
|
||||||
|
|
||||||
HttpServletRequest servletRequest = getHttpServletRequest(request);
|
|
||||||
HttpServletResponse servletResponse = getHttpServletResponse(response);
|
|
||||||
|
|
||||||
final ServletWebSocketHttpExchange exchange = createHttpExchange(servletRequest, servletResponse);
|
|
||||||
exchange.putAttachment(HandshakeUtil.PATH_PARAMS, Collections.<String, String>emptyMap());
|
|
||||||
|
|
||||||
ServerWebSocketContainer wsContainer = (ServerWebSocketContainer) getContainer(servletRequest);
|
|
||||||
final EndpointSessionHandler endpointSessionHandler = new EndpointSessionHandler(wsContainer);
|
|
||||||
|
|
||||||
final ConfiguredServerEndpoint configuredServerEndpoint = createConfiguredServerEndpoint(
|
|
||||||
selectedProtocol, selectedExtensions, endpoint, servletRequest);
|
|
||||||
|
|
||||||
final Handshake handshake = getHandshakeToUse(exchange, configuredServerEndpoint);
|
|
||||||
|
|
||||||
exchange.upgradeChannel(new HttpUpgradeListener() {
|
|
||||||
@Override
|
|
||||||
public void handleUpgrade(StreamConnection connection, HttpServerExchange serverExchange) {
|
|
||||||
Object bufferPool = ReflectionUtils.invokeMethod(getBufferPoolMethod, exchange);
|
|
||||||
WebSocketChannel channel = (WebSocketChannel) ReflectionUtils.invokeMethod(
|
|
||||||
createChannelMethod, handshake, exchange, connection, bufferPool);
|
|
||||||
if (peerConnections != null) {
|
|
||||||
peerConnections.add(channel);
|
|
||||||
}
|
|
||||||
endpointSessionHandler.onConnect(exchange, channel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
handshake.handshake(exchange);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ServletWebSocketHttpExchange createHttpExchange(HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
try {
|
|
||||||
return (this.peerConnections != null ?
|
|
||||||
exchangeConstructor.newInstance(request, response, this.peerConnections) :
|
|
||||||
exchangeConstructor.newInstance(request, response));
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new HandshakeFailureException("Failed to instantiate ServletWebSocketHttpExchange", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Handshake getHandshakeToUse(ServletWebSocketHttpExchange exchange, ConfiguredServerEndpoint endpoint) {
|
|
||||||
Handshake handshake = new JsrHybi13Handshake(endpoint);
|
|
||||||
if (handshake.matches(exchange)) {
|
|
||||||
return handshake;
|
|
||||||
}
|
|
||||||
handshake = new JsrHybi08Handshake(endpoint);
|
|
||||||
if (handshake.matches(exchange)) {
|
|
||||||
return handshake;
|
|
||||||
}
|
|
||||||
handshake = new JsrHybi07Handshake(endpoint);
|
|
||||||
if (handshake.matches(exchange)) {
|
|
||||||
return handshake;
|
|
||||||
}
|
|
||||||
// Should never occur
|
|
||||||
throw new HandshakeFailureException("No matching Undertow Handshake found: " + exchange.getRequestHeaders());
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConfiguredServerEndpoint createConfiguredServerEndpoint(String selectedProtocol,
|
|
||||||
List<Extension> selectedExtensions, Endpoint endpoint, HttpServletRequest servletRequest) {
|
|
||||||
|
|
||||||
String path = servletRequest.getRequestURI(); // shouldn't matter
|
|
||||||
ServerEndpointRegistration endpointRegistration = new ServerEndpointRegistration(path, endpoint);
|
|
||||||
endpointRegistration.setSubprotocols(Collections.singletonList(selectedProtocol));
|
|
||||||
endpointRegistration.setExtensions(selectedExtensions);
|
|
||||||
|
|
||||||
EncodingFactory encodingFactory = new EncodingFactory(
|
|
||||||
Collections.<Class<?>, List<InstanceFactory<? extends Encoder>>>emptyMap(),
|
|
||||||
Collections.<Class<?>, List<InstanceFactory<? extends Decoder>>>emptyMap(),
|
|
||||||
Collections.<Class<?>, List<InstanceFactory<? extends Encoder>>>emptyMap(),
|
|
||||||
Collections.<Class<?>, List<InstanceFactory<? extends Decoder>>>emptyMap());
|
|
||||||
try {
|
|
||||||
return (endpointConstructorWithEndpointFactory ?
|
|
||||||
endpointConstructor.newInstance(endpointRegistration,
|
|
||||||
new EndpointInstanceFactory(endpoint), null, encodingFactory, null) :
|
|
||||||
endpointConstructor.newInstance(endpointRegistration,
|
|
||||||
new EndpointInstanceFactory(endpoint), null, encodingFactory));
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new HandshakeFailureException("Failed to instantiate ConfiguredServerEndpoint", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class EndpointInstanceFactory implements InstanceFactory<Endpoint> {
|
|
||||||
|
|
||||||
private final Endpoint endpoint;
|
|
||||||
|
|
||||||
public EndpointInstanceFactory(Endpoint endpoint) {
|
|
||||||
this.endpoint = endpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InstanceHandle<Endpoint> createInstance() throws InstantiationException {
|
|
||||||
return new InstanceHandle<Endpoint>() {
|
|
||||||
@Override
|
|
||||||
public Endpoint getInstance() {
|
|
||||||
return endpoint;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void release() {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -46,33 +46,22 @@ import org.springframework.web.socket.server.HandshakeFailureException;
|
||||||
* Supports 12.1.3 as well as 12.2.1, as of Spring Framework 4.2.3.
|
* Supports 12.1.3 as well as 12.2.1, as of Spring Framework 4.2.3.
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
*/
|
*/
|
||||||
public class WebLogicRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeStrategy {
|
public class WebLogicRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeStrategy {
|
||||||
|
|
||||||
private static final boolean WLS_12_1_3 = isWebLogic1213();
|
|
||||||
|
|
||||||
private static final TyrusEndpointHelper endpointHelper =
|
|
||||||
(WLS_12_1_3 ? new Tyrus135EndpointHelper() : new Tyrus17EndpointHelper());
|
|
||||||
|
|
||||||
private static final TyrusMuxableWebSocketHelper webSocketHelper = new TyrusMuxableWebSocketHelper();
|
private static final TyrusMuxableWebSocketHelper webSocketHelper = new TyrusMuxableWebSocketHelper();
|
||||||
|
|
||||||
private static final WebLogicServletWriterHelper servletWriterHelper = new WebLogicServletWriterHelper();
|
private static final WebLogicServletWriterHelper servletWriterHelper = new WebLogicServletWriterHelper();
|
||||||
|
|
||||||
private static final Connection.CloseListener noOpCloseListener = new Connection.CloseListener() {
|
private static final Connection.CloseListener noOpCloseListener = new Connection.CloseListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close(CloseReason reason) {
|
public void close(CloseReason reason) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected TyrusEndpointHelper getEndpointHelper() {
|
|
||||||
return endpointHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleSuccess(HttpServletRequest request, HttpServletResponse response,
|
protected void handleSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||||
UpgradeInfo upgradeInfo, TyrusUpgradeResponse upgradeResponse) throws IOException, ServletException {
|
UpgradeInfo upgradeInfo, TyrusUpgradeResponse upgradeResponse) throws IOException, ServletException {
|
||||||
|
|
@ -94,7 +83,7 @@ public class WebLogicRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeS
|
||||||
response.flushBuffer();
|
response.flushBuffer();
|
||||||
|
|
||||||
boolean isProtected = request.getUserPrincipal() != null;
|
boolean isProtected = request.getUserPrincipal() != null;
|
||||||
Writer servletWriter = servletWriterHelper.newInstance(response, webSocket, isProtected);
|
Writer servletWriter = servletWriterHelper.newInstance(webSocket, isProtected);
|
||||||
Connection connection = upgradeInfo.createConnection(servletWriter, noOpCloseListener);
|
Connection connection = upgradeInfo.createConnection(servletWriter, noOpCloseListener);
|
||||||
new BeanWrapperImpl(webSocket).setPropertyValue("connection", connection);
|
new BeanWrapperImpl(webSocket).setPropertyValue("connection", connection);
|
||||||
new BeanWrapperImpl(servletWriter).setPropertyValue("connection", connection);
|
new BeanWrapperImpl(servletWriter).setPropertyValue("connection", connection);
|
||||||
|
|
@ -102,20 +91,6 @@ public class WebLogicRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static boolean isWebLogic1213() {
|
|
||||||
try {
|
|
||||||
type("weblogic.websocket.tyrus.TyrusMuxableWebSocket").getDeclaredConstructor(
|
|
||||||
type("weblogic.servlet.internal.MuxableSocketHTTP"));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (NoSuchMethodException ex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException ex) {
|
|
||||||
throw new IllegalStateException("No compatible WebSocket version found", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Class<?> type(String className) throws ClassNotFoundException {
|
private static Class<?> type(String className) throws ClassNotFoundException {
|
||||||
return WebLogicRequestUpgradeStrategy.class.getClassLoader().loadClass(className);
|
return WebLogicRequestUpgradeStrategy.class.getClassLoader().loadClass(className);
|
||||||
}
|
}
|
||||||
|
|
@ -153,17 +128,11 @@ public class WebLogicRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeS
|
||||||
try {
|
try {
|
||||||
type = type("weblogic.websocket.tyrus.TyrusMuxableWebSocket");
|
type = type("weblogic.websocket.tyrus.TyrusMuxableWebSocket");
|
||||||
|
|
||||||
if (WLS_12_1_3) {
|
|
||||||
constructor = type.getDeclaredConstructor(type("weblogic.servlet.internal.MuxableSocketHTTP"));
|
|
||||||
subjectHelper = null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
constructor = type.getDeclaredConstructor(
|
constructor = type.getDeclaredConstructor(
|
||||||
type("weblogic.servlet.internal.MuxableSocketHTTP"),
|
type("weblogic.servlet.internal.MuxableSocketHTTP"),
|
||||||
type("weblogic.websocket.tyrus.CoherenceServletFilterService"),
|
type("weblogic.websocket.tyrus.CoherenceServletFilterService"),
|
||||||
type("weblogic.servlet.spi.SubjectHandle"));
|
type("weblogic.servlet.spi.SubjectHandle"));
|
||||||
subjectHelper = new SubjectHelper();
|
subjectHelper = new SubjectHelper();
|
||||||
}
|
|
||||||
|
|
||||||
upgradeMethod = type.getMethod("upgrade", type("weblogic.socket.MuxableSocket"), ServletContext.class);
|
upgradeMethod = type.getMethod("upgrade", type("weblogic.socket.MuxableSocket"), ServletContext.class);
|
||||||
readEventMethod = type.getMethod("registerForReadEvent");
|
readEventMethod = type.getMethod("registerForReadEvent");
|
||||||
|
|
@ -175,8 +144,7 @@ public class WebLogicRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeS
|
||||||
|
|
||||||
private Object newInstance(HttpServletRequest request, Object httpSocket) {
|
private Object newInstance(HttpServletRequest request, Object httpSocket) {
|
||||||
try {
|
try {
|
||||||
Object[] args = (WLS_12_1_3 ? new Object[] {httpSocket} :
|
Object[] args = new Object[] {httpSocket, null, subjectHelper.getSubject(request)};
|
||||||
new Object[] {httpSocket, null, subjectHelper.getSubject(request)});
|
|
||||||
return constructor.newInstance(args);
|
return constructor.newInstance(args);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
|
|
@ -263,13 +231,7 @@ public class WebLogicRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeS
|
||||||
Class<?> writerType = type("weblogic.websocket.tyrus.TyrusServletWriter");
|
Class<?> writerType = type("weblogic.websocket.tyrus.TyrusServletWriter");
|
||||||
Class<?> listenerType = type("weblogic.websocket.tyrus.TyrusServletWriter$CloseListener");
|
Class<?> listenerType = type("weblogic.websocket.tyrus.TyrusServletWriter$CloseListener");
|
||||||
Class<?> webSocketType = TyrusMuxableWebSocketHelper.type;
|
Class<?> webSocketType = TyrusMuxableWebSocketHelper.type;
|
||||||
Class<HttpServletResponse> responseType = HttpServletResponse.class;
|
constructor = writerType.getDeclaredConstructor(webSocketType, listenerType, boolean.class);
|
||||||
|
|
||||||
Class<?>[] argTypes = (WLS_12_1_3 ?
|
|
||||||
new Class<?>[] {webSocketType, responseType, listenerType, boolean.class} :
|
|
||||||
new Class<?>[] {webSocketType, listenerType, boolean.class});
|
|
||||||
|
|
||||||
constructor = writerType.getDeclaredConstructor(argTypes);
|
|
||||||
ReflectionUtils.makeAccessible(constructor);
|
ReflectionUtils.makeAccessible(constructor);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
|
|
@ -277,13 +239,9 @@ public class WebLogicRequestUpgradeStrategy extends AbstractTyrusRequestUpgradeS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Writer newInstance(HttpServletResponse response, Object webSocket, boolean isProtected) {
|
private Writer newInstance(Object webSocket, boolean isProtected) {
|
||||||
try {
|
try {
|
||||||
Object[] args = (WLS_12_1_3 ?
|
return (Writer) constructor.newInstance(webSocket, null, isProtected);
|
||||||
new Object[] {webSocket, response, null, isProtected} :
|
|
||||||
new Object[] {webSocket, null, isProtected});
|
|
||||||
|
|
||||||
return (Writer) constructor.newInstance(args);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new HandshakeFailureException("Failed to create TyrusServletWriter", ex);
|
throw new HandshakeFailureException("Failed to create TyrusServletWriter", ex);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue