Drop support for Jetty 9.3 and OkHttp 2.x

Issue: SPR-15038
This commit is contained in:
Juergen Hoeller
2017-03-06 17:54:02 +01:00
parent 37726f4214
commit 47c4cf7abf
10 changed files with 50 additions and 704 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@@ -17,7 +17,6 @@
package org.springframework.web.socket.adapter.jetty;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.Principal;
@@ -28,15 +27,12 @@ import java.util.Map;
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
import org.springframework.http.HttpHeaders;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PingMessage;
@@ -47,7 +43,7 @@ import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.adapter.AbstractWebSocketSession;
/**
* A {@link WebSocketSession} for use with the Jetty 9.3/9.4 WebSocket API.
* A {@link WebSocketSession} for use with the Jetty 9.4 WebSocket API.
*
* @author Phillip Webb
* @author Rossen Stoyanchev
@@ -57,36 +53,6 @@ import org.springframework.web.socket.adapter.AbstractWebSocketSession;
*/
public class JettyWebSocketSession extends AbstractWebSocketSession<Session> {
// As of Jetty 9.4, UpgradeRequest and UpgradeResponse are interfaces instead of classes
private static final boolean directInterfaceCalls;
private static Method getUpgradeRequest;
private static Method getUpgradeResponse;
private static Method getRequestURI;
private static Method getHeaders;
private static Method getUserPrincipal;
private static Method getAcceptedSubProtocol;
private static Method getExtensions;
static {
directInterfaceCalls = UpgradeRequest.class.isInterface();
if (!directInterfaceCalls) {
try {
getUpgradeRequest = Session.class.getMethod("getUpgradeRequest");
getUpgradeResponse = Session.class.getMethod("getUpgradeResponse");
getRequestURI = UpgradeRequest.class.getMethod("getRequestURI");
getHeaders = UpgradeRequest.class.getMethod("getHeaders");
getUserPrincipal = UpgradeRequest.class.getMethod("getUserPrincipal");
getAcceptedSubProtocol = UpgradeResponse.class.getMethod("getAcceptedSubProtocol");
getExtensions = UpgradeResponse.class.getMethod("getExtensions");
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException("Incompatible Jetty API", ex);
}
}
}
private String id;
private URI uri;
@@ -201,31 +167,23 @@ public class JettyWebSocketSession extends AbstractWebSocketSession<Session> {
@Override
public void initializeNativeSession(Session session) {
super.initializeNativeSession(session);
if (directInterfaceCalls) {
initializeJettySessionDirectly(session);
}
else {
initializeJettySessionReflectively(session);
}
}
private void initializeJettySessionDirectly(Session session) {
this.id = ObjectUtils.getIdentityHexString(getNativeSession());
this.uri = session.getUpgradeRequest().getRequestURI();
this.headers = new HttpHeaders();
this.headers.putAll(session.getUpgradeRequest().getHeaders());
this.headers = HttpHeaders.readOnlyHttpHeaders(this.headers);
HttpHeaders headers = new HttpHeaders();
headers.putAll(session.getUpgradeRequest().getHeaders());
this.headers = HttpHeaders.readOnlyHttpHeaders(headers);
this.acceptedProtocol = session.getUpgradeResponse().getAcceptedSubProtocol();
List<ExtensionConfig> jettyExtensions = session.getUpgradeResponse().getExtensions();
if (!CollectionUtils.isEmpty(jettyExtensions)) {
this.extensions = new ArrayList<>(jettyExtensions.size());
List<WebSocketExtension> extensions = new ArrayList<>(jettyExtensions.size());
for (ExtensionConfig jettyExtension : jettyExtensions) {
this.extensions.add(new WebSocketExtension(jettyExtension.getName(), jettyExtension.getParameters()));
extensions.add(new WebSocketExtension(jettyExtension.getName(), jettyExtension.getParameters()));
}
this.extensions = Collections.unmodifiableList(this.extensions);
this.extensions = Collections.unmodifiableList(extensions);
}
else {
this.extensions = Collections.emptyList();
@@ -236,37 +194,6 @@ public class JettyWebSocketSession extends AbstractWebSocketSession<Session> {
}
}
@SuppressWarnings("unchecked")
private void initializeJettySessionReflectively(Session session) {
Object request = ReflectionUtils.invokeMethod(getUpgradeRequest, session);
Object response = ReflectionUtils.invokeMethod(getUpgradeResponse, session);
this.id = ObjectUtils.getIdentityHexString(getNativeSession());
this.uri = (URI) ReflectionUtils.invokeMethod(getRequestURI, request);
this.headers = new HttpHeaders();
this.headers.putAll((Map<String, List<String>>) ReflectionUtils.invokeMethod(getHeaders, request));
this.headers = HttpHeaders.readOnlyHttpHeaders(this.headers);
this.acceptedProtocol = (String) ReflectionUtils.invokeMethod(getAcceptedSubProtocol, response);
List<ExtensionConfig> extensions = (List<ExtensionConfig>) ReflectionUtils.invokeMethod(getExtensions, response);
if (!CollectionUtils.isEmpty(extensions)) {
this.extensions = new ArrayList<>(extensions.size());
for (ExtensionConfig extension : extensions) {
this.extensions.add(new WebSocketExtension(extension.getName(), extension.getParameters()));
}
this.extensions = Collections.unmodifiableList(this.extensions);
}
else {
this.extensions = Collections.emptyList();
}
if (this.user == null) {
this.user = (Principal) ReflectionUtils.invokeMethod(getUserPrincipal, request);
}
}
@Override
protected void sendTextMessage(TextMessage message) throws IOException {

View File

@@ -41,7 +41,6 @@ import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.socket.WebSocketExtension;
@@ -53,8 +52,8 @@ import org.springframework.web.socket.server.HandshakeFailureException;
import org.springframework.web.socket.server.RequestUpgradeStrategy;
/**
* A {@link RequestUpgradeStrategy} for use with Jetty 9.3 and 9.4. Based on
* Jetty's internal {@code org.eclipse.jetty.websocket.server.WebSocketHandler} class.
* A {@link RequestUpgradeStrategy} for use with Jetty 9.4. Based on Jetty's
* internal {@code org.eclipse.jetty.websocket.server.WebSocketHandler} class.
*
* @author Phillip Webb
* @author Rossen Stoyanchev
@@ -68,11 +67,9 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
new NamedThreadLocal<>("WebSocketHandlerContainer");
// Configurable factory adapter due to Jetty 9.3.15+ API differences:
// using WebSocketServerFactory(ServletContext) as a version indicator
private final WebSocketServerFactoryAdapter factoryAdapter =
(ClassUtils.hasConstructor(WebSocketServerFactory.class, ServletContext.class) ?
new ModernJettyWebSocketServerFactoryAdapter() : new LegacyJettyWebSocketServerFactoryAdapter());
private WebSocketPolicy policy;
private WebSocketServerFactory factory;
private ServletContext servletContext;
@@ -86,7 +83,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
* its default constructor thus using a default {@link WebSocketPolicy}.
*/
public JettyRequestUpgradeStrategy() {
this.factoryAdapter.setPolicy(WebSocketPolicy.newServerPolicy());
this.policy = WebSocketPolicy.newServerPolicy();
}
/**
@@ -97,7 +94,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
*/
public JettyRequestUpgradeStrategy(WebSocketPolicy policy) {
Assert.notNull(policy, "WebSocketPolicy must not be null");
this.factoryAdapter.setPolicy(policy);
this.policy = policy;
}
/**
@@ -106,7 +103,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
*/
public JettyRequestUpgradeStrategy(WebSocketServerFactory factory) {
Assert.notNull(factory, "WebSocketServerFactory must not be null");
this.factoryAdapter.setFactory(factory);
this.factory = factory;
}
@@ -120,7 +117,20 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
if (!isRunning()) {
this.running = true;
try {
this.factoryAdapter.start();
if (this.factory == null) {
this.factory = new WebSocketServerFactory(servletContext, this.policy);
}
this.factory.setCreator(new WebSocketCreator() {
@Override
public Object createWebSocket(ServletUpgradeRequest request, ServletUpgradeResponse response) {
WebSocketHandlerContainer container = containerHolder.get();
Assert.state(container != null, "Expected WebSocketHandlerContainer");
response.setAcceptedSubProtocol(container.getSelectedProtocol());
response.setExtensions(container.getExtensionConfigs());
return container.getHandler();
}
});
this.factory.start();
}
catch (Throwable ex) {
throw new IllegalStateException("Unable to start Jetty WebSocketServerFactory", ex);
@@ -132,11 +142,13 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
public void stop() {
if (isRunning()) {
this.running = false;
try {
this.factoryAdapter.stop();
}
catch (Throwable ex) {
throw new IllegalStateException("Unable to stop Jetty WebSocketServerFactory", ex);
if (this.factory != null) {
try {
this.factory.stop();
}
catch (Throwable ex) {
throw new IllegalStateException("Unable to stop Jetty WebSocketServerFactory", ex);
}
}
}
}
@@ -161,7 +173,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
}
private List<WebSocketExtension> buildWebSocketExtensions() {
Set<String> names = this.factoryAdapter.getFactory().getExtensionFactory().getExtensionNames();
Set<String> names = this.factory.getExtensionFactory().getExtensionNames();
List<WebSocketExtension> result = new ArrayList<>(names.size());
for (String name : names) {
result.add(new WebSocketExtension(name));
@@ -180,8 +192,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
Assert.isInstanceOf(ServletServerHttpResponse.class, response, "ServletServerHttpResponse required");
HttpServletResponse servletResponse = ((ServletServerHttpResponse) response).getServletResponse();
Assert.isTrue(this.factoryAdapter.getFactory().isUpgradeRequest(servletRequest, servletResponse),
"Not a WebSocket handshake");
Assert.isTrue(this.factory.isUpgradeRequest(servletRequest, servletResponse), "Not a WebSocket handshake");
JettyWebSocketSession session = new JettyWebSocketSession(attributes, user);
JettyWebSocketHandlerAdapter handlerAdapter = new JettyWebSocketHandlerAdapter(wsHandler, session);
@@ -191,7 +202,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
try {
containerHolder.set(container);
this.factoryAdapter.getFactory().acceptWebSocket(servletRequest, servletResponse);
this.factory.acceptWebSocket(servletRequest, servletResponse);
}
catch (IOException ex) {
throw new HandshakeFailureException(
@@ -240,93 +251,4 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
}
}
private static abstract class WebSocketServerFactoryAdapter {
private WebSocketPolicy policy;
private WebSocketServerFactory factory;
public void setPolicy(WebSocketPolicy policy) {
this.policy = policy;
}
public void setFactory(WebSocketServerFactory factory) {
this.factory = factory;
}
public WebSocketServerFactory getFactory() {
return this.factory;
}
public void start() throws Exception {
if (this.factory == null) {
this.factory = createFactory(this.policy);
}
this.factory.setCreator(new WebSocketCreator() {
@Override
public Object createWebSocket(ServletUpgradeRequest request, ServletUpgradeResponse response) {
WebSocketHandlerContainer container = containerHolder.get();
Assert.state(container != null, "Expected WebSocketHandlerContainer");
response.setAcceptedSubProtocol(container.getSelectedProtocol());
response.setExtensions(container.getExtensionConfigs());
return container.getHandler();
}
});
startFactory(this.factory);
}
public void stop() throws Exception {
if (this.factory != null) {
stopFactory(this.factory);
}
}
protected abstract WebSocketServerFactory createFactory(WebSocketPolicy policy) throws Exception;
protected abstract void startFactory(WebSocketServerFactory factory) throws Exception;
protected abstract void stopFactory(WebSocketServerFactory factory) throws Exception;
}
// Jetty 9.3.15+
private class ModernJettyWebSocketServerFactoryAdapter extends WebSocketServerFactoryAdapter {
@Override
protected WebSocketServerFactory createFactory(WebSocketPolicy policy) throws Exception {
return new WebSocketServerFactory(servletContext, policy);
}
@Override
protected void startFactory(WebSocketServerFactory factory) throws Exception {
factory.start();
}
@Override
protected void stopFactory(WebSocketServerFactory factory) throws Exception {
factory.stop();
}
}
// Jetty <9.3.15
private class LegacyJettyWebSocketServerFactoryAdapter extends WebSocketServerFactoryAdapter {
@Override
protected WebSocketServerFactory createFactory(WebSocketPolicy policy) throws Exception {
return WebSocketServerFactory.class.getConstructor(WebSocketPolicy.class).newInstance(policy);
}
@Override
protected void startFactory(WebSocketServerFactory factory) throws Exception {
WebSocketServerFactory.class.getMethod("init", ServletContext.class).invoke(factory, servletContext);
}
@Override
protected void stopFactory(WebSocketServerFactory factory) throws Exception {
WebSocketServerFactory.class.getMethod("cleanup").invoke(factory);
}
}
}