From 30ab5953f973e56bbcdc971c700657da5cc2e446 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 28 Mar 2013 12:03:33 -0400 Subject: [PATCH] Add EndpointRequestUpgradeStrategy Now there is just one EndpointHandshakeRequestHandler that works on different runtimes. --- ...intExporter.java => EndpointExporter.java} | 6 +- .../EndpointHandshakeRequestHandler.java | 83 +++++++++++++++++++ ...tration.java => EndpointRegistration.java} | 20 ++--- .../EndpointRequestUpgradeStrategy.java | 35 ++++++++ ...rter.java => ServletEndpointExporter.java} | 5 +- .../TomcatHandshakeRequestHandler.java | 79 ------------------ .../TomcatRequestUpgradeStrategy.java | 61 ++++++++++++++ .../server/endpoint/package-info.java | 2 +- 8 files changed, 197 insertions(+), 94 deletions(-) rename spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/{ServerEndpointExporter.java => EndpointExporter.java} (94%) create mode 100644 spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointHandshakeRequestHandler.java rename spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/{ServerEndpointRegistration.java => EndpointRegistration.java} (89%) create mode 100644 spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointRequestUpgradeStrategy.java rename spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/{ServletServerEndpointExporter.java => ServletEndpointExporter.java} (88%) delete mode 100644 spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/TomcatHandshakeRequestHandler.java create mode 100644 spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/TomcatRequestUpgradeStrategy.java diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServerEndpointExporter.java b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointExporter.java similarity index 94% rename from spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServerEndpointExporter.java rename to spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointExporter.java index bb82114484..5a601bfe88 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServerEndpointExporter.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointExporter.java @@ -33,12 +33,14 @@ import org.springframework.util.Assert; * Java WebSocket runtime and also configures the underlying * {@link javax.websocket.server.ServerContainer}. * + *

If the runtime is a Servlet container, use {@link ServletEndpointExporter}. + * * @author Rossen Stoyanchev * @since 4.0 */ -public class ServerEndpointExporter implements BeanPostProcessor, InitializingBean { +public class EndpointExporter implements BeanPostProcessor, InitializingBean { - private static Log logger = LogFactory.getLog(ServerEndpointExporter.class); + private static Log logger = LogFactory.getLog(EndpointExporter.class); private Long maxSessionIdleTimeout; diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointHandshakeRequestHandler.java b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointHandshakeRequestHandler.java new file mode 100644 index 0000000000..aae44c148c --- /dev/null +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointHandshakeRequestHandler.java @@ -0,0 +1,83 @@ +/* + * Copyright 2002-2013 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.websocket.server.endpoint; + +import javax.websocket.Endpoint; + +import org.springframework.beans.BeanUtils; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.util.ClassUtils; +import org.springframework.websocket.WebSocketHandler; +import org.springframework.websocket.endpoint.StandardWebSocketHandlerAdapter; +import org.springframework.websocket.server.AbstractHandshakeRequestHandler; + + +/** + * + * @author Rossen Stoyanchev + * @since 4.0 + */ +public class EndpointHandshakeRequestHandler extends AbstractHandshakeRequestHandler { + + private static final boolean tomcatWebSocketPresent = ClassUtils.isPresent( + "org.apache.tomcat.websocket.server.WsHandshakeRequest", EndpointHandshakeRequestHandler.class.getClassLoader()); + + private final EndpointRegistration endpointRegistration; + + private final EndpointRequestUpgradeStrategy upgradeStrategy; + + + public EndpointHandshakeRequestHandler(WebSocketHandler webSocketHandler) { + this(new StandardWebSocketHandlerAdapter(webSocketHandler)); + } + + public EndpointHandshakeRequestHandler(Endpoint endpoint) { + this.endpointRegistration = new EndpointRegistration("/dummy", endpoint); + this.upgradeStrategy = createRequestUpgradeStrategy(); + } + + private static EndpointRequestUpgradeStrategy createRequestUpgradeStrategy() { + String className; + if (tomcatWebSocketPresent) { + className = "org.springframework.websocket.server.endpoint.TomcatRequestUpgradeStrategy"; + } + else { + throw new IllegalStateException("No suitable EndpointRequestUpgradeStrategy"); + } + try { + Class clazz = ClassUtils.forName(className, EndpointHandshakeRequestHandler.class.getClassLoader()); + return (EndpointRequestUpgradeStrategy) BeanUtils.instantiateClass(clazz.getConstructor()); + } + catch (Throwable t) { + throw new IllegalStateException("Failed to instantiate " + className, t); + } + } + + public EndpointRegistration getEndpointRegistration() { + return this.endpointRegistration; + } + + @Override + public void doHandshakeInternal(ServerHttpRequest request, ServerHttpResponse response, String protocol) + throws Exception { + + logger.debug("Upgrading HTTP request"); + this.upgradeStrategy.upgrade(request, response, protocol, this.endpointRegistration); + } + +} \ No newline at end of file diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServerEndpointRegistration.java b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointRegistration.java similarity index 89% rename from spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServerEndpointRegistration.java rename to spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointRegistration.java index 8179253e6b..bbc4d6b814 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServerEndpointRegistration.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointRegistration.java @@ -46,13 +46,13 @@ import org.springframework.websocket.endpoint.StandardWebSocketHandlerAdapter; * which case it will be adapted via {@link StandardWebSocketHandlerAdapter}. * *

- * Beans of this type are detected by {@link ServerEndpointExporter} and + * Beans of this type are detected by {@link EndpointExporter} and * registered with a Java WebSocket runtime at startup. * * @author Rossen Stoyanchev * @since 4.0 */ -public class ServerEndpointRegistration implements ServerEndpointConfig, BeanFactoryAware { +public class EndpointRegistration implements ServerEndpointConfig, BeanFactoryAware { private final String path; @@ -69,14 +69,14 @@ public class ServerEndpointRegistration implements ServerEndpointConfig, BeanFac private final Configurator configurator = new Configurator() {}; - public ServerEndpointRegistration(String path, String beanName) { + public EndpointRegistration(String path, String beanName) { Assert.hasText(path, "path must not be empty"); Assert.notNull(beanName, "beanName is required"); this.path = path; this.bean = beanName; } - public ServerEndpointRegistration(String path, Object bean) { + public EndpointRegistration(String path, Object bean) { Assert.hasText(path, "path must not be empty"); Assert.notNull(bean, "bean is required"); this.path = path; @@ -104,7 +104,7 @@ public class ServerEndpointRegistration implements ServerEndpointConfig, BeanFac } } - protected Endpoint getEndpoint() { + public Endpoint getEndpoint() { Object bean = this.bean; if (this.bean instanceof String) { bean = this.beanFactory.getBean((String) this.bean); @@ -166,23 +166,23 @@ public class ServerEndpointRegistration implements ServerEndpointConfig, BeanFac @SuppressWarnings("unchecked") @Override public T getEndpointInstance(Class clazz) throws InstantiationException { - return (T) ServerEndpointRegistration.this.getEndpoint(); + return (T) EndpointRegistration.this.getEndpoint(); } @Override public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { - ServerEndpointRegistration.this.modifyHandshake(request, response); + EndpointRegistration.this.modifyHandshake(request, response); } @Override public boolean checkOrigin(String originHeaderValue) { - return ServerEndpointRegistration.this.checkOrigin(originHeaderValue); + return EndpointRegistration.this.checkOrigin(originHeaderValue); } @Override public String getNegotiatedSubprotocol(List supported, List requested) { - return ServerEndpointRegistration.this.selectSubProtocol(requested); + return EndpointRegistration.this.selectSubProtocol(requested); } @Override public List getNegotiatedExtensions(List installed, List requested) { - return ServerEndpointRegistration.this.selectExtensions(requested); + return EndpointRegistration.this.selectExtensions(requested); } }; } diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointRequestUpgradeStrategy.java b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointRequestUpgradeStrategy.java new file mode 100644 index 0000000000..745001b206 --- /dev/null +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/EndpointRequestUpgradeStrategy.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2013 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.websocket.server.endpoint; + +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; + + +/** + * A strategy for performing the actual request upgrade after the handshake checks have + * passed, encapsulating runtime-specific steps of the handshake. + * + * @author Rossen Stoyanchev + * @since 4.0 + */ +public interface EndpointRequestUpgradeStrategy { + + void upgrade(ServerHttpRequest request, ServerHttpResponse response, String protocol, + EndpointRegistration registration) throws Exception; + +} diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServletServerEndpointExporter.java b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServletEndpointExporter.java similarity index 88% rename from spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServletServerEndpointExporter.java rename to spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServletEndpointExporter.java index 2c7ca73808..2e36774f79 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServletServerEndpointExporter.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/ServletEndpointExporter.java @@ -27,7 +27,7 @@ import org.springframework.web.context.ServletContextAware; * @author Rossen Stoyanchev * @since 4.0 */ -public class ServletServerEndpointExporter extends ServerEndpointExporter implements ServletContextAware { +public class ServletEndpointExporter extends EndpointExporter implements ServletContextAware { private ServletContext servletContext; @@ -43,7 +43,8 @@ public class ServletServerEndpointExporter extends ServerEndpointExporter implem @Override public void afterPropertiesSet() throws Exception { - // TODO: remove hard dependency on Tomcat (see Tomcat's WsListener) + + // TODO: this is needed (see WsListener) but remove hard dependency WsServerContainer sc = WsServerContainer.getServerContainer(); sc.setServletContext(this.servletContext); diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/TomcatHandshakeRequestHandler.java b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/TomcatHandshakeRequestHandler.java deleted file mode 100644 index a185f67ad3..0000000000 --- a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/TomcatHandshakeRequestHandler.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2002-2013 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.websocket.server.endpoint; - -import java.lang.reflect.Method; -import java.util.Collections; - -import javax.servlet.http.HttpServletRequest; -import javax.websocket.Endpoint; -import javax.websocket.server.ServerEndpointConfig; - -import org.apache.tomcat.websocket.server.WsHandshakeRequest; -import org.apache.tomcat.websocket.server.WsHttpUpgradeHandler; -import org.apache.tomcat.websocket.server.WsServerContainer; -import org.springframework.http.server.ServerHttpRequest; -import org.springframework.http.server.ServerHttpResponse; -import org.springframework.http.server.ServletServerHttpRequest; -import org.springframework.util.Assert; -import org.springframework.util.ReflectionUtils; -import org.springframework.websocket.WebSocketHandler; -import org.springframework.websocket.endpoint.StandardWebSocketHandlerAdapter; -import org.springframework.websocket.server.AbstractHandshakeRequestHandler; - - -/** - * - * @author Rossen Stoyanchev - * @since 4.0 - */ -public class TomcatHandshakeRequestHandler extends AbstractHandshakeRequestHandler { - - private final Endpoint endpoint; - - private final ServerEndpointConfig endpointConfig; - - - public TomcatHandshakeRequestHandler(WebSocketHandler webSocketHandler) { - this(new StandardWebSocketHandlerAdapter(webSocketHandler)); - } - - public TomcatHandshakeRequestHandler(Endpoint endpoint) { - this.endpoint = endpoint; - this.endpointConfig = new ServerEndpointRegistration("/dummy", this.endpoint); - } - - @Override - public void doHandshakeInternal(ServerHttpRequest request, ServerHttpResponse response, String protocol) throws Exception { - - logger.debug("Upgrading HTTP request"); - - Assert.isTrue(request instanceof ServletServerHttpRequest); - HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest(); - - WsHandshakeRequest wsRequest = new WsHandshakeRequest(servletRequest); - Method method = ReflectionUtils.findMethod(WsHandshakeRequest.class, "finished"); - ReflectionUtils.makeAccessible(method); - method.invoke(wsRequest); - - WsHttpUpgradeHandler wsHandler = servletRequest.upgrade(WsHttpUpgradeHandler.class); - - wsHandler.preInit(this.endpoint, this.endpointConfig, WsServerContainer.getServerContainer(), - wsRequest, protocol, Collections. emptyMap(), servletRequest.isSecure()); - } - -} \ No newline at end of file diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/TomcatRequestUpgradeStrategy.java b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/TomcatRequestUpgradeStrategy.java new file mode 100644 index 0000000000..b25c1a47c3 --- /dev/null +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/TomcatRequestUpgradeStrategy.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2013 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.websocket.server.endpoint; + +import java.lang.reflect.Method; +import java.util.Collections; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.tomcat.websocket.server.WsHandshakeRequest; +import org.apache.tomcat.websocket.server.WsHttpUpgradeHandler; +import org.apache.tomcat.websocket.server.WsServerContainer; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + + +/** + * + * @author Rossen Stoyanchev + * @since 4.0 + */ +public class TomcatRequestUpgradeStrategy implements EndpointRequestUpgradeStrategy { + + + @Override + public void upgrade(ServerHttpRequest request, ServerHttpResponse response, String protocol, + EndpointRegistration registration) throws Exception { + + Assert.isTrue(request instanceof ServletServerHttpRequest); + HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest(); + + WsHttpUpgradeHandler wsHandler = servletRequest.upgrade(WsHttpUpgradeHandler.class); + + WsHandshakeRequest wsRequest = new WsHandshakeRequest(servletRequest); + Method method = ReflectionUtils.findMethod(WsHandshakeRequest.class, "finished"); + ReflectionUtils.makeAccessible(method); + method.invoke(wsRequest); + + wsHandler.preInit(registration.getEndpoint(), registration, + WsServerContainer.getServerContainer(), wsRequest, protocol, + Collections. emptyMap(), servletRequest.isSecure()); + } + +} diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/package-info.java b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/package-info.java index a5f66584f8..3ede1f92bc 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/package-info.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/endpoint/package-info.java @@ -1,7 +1,7 @@ /** * - * Server-specific support for working with standard Java WebSocket Endpoint's. + * Server-specific support for configuring and adapting standard Java WebSocket endpoint's. * */ package org.springframework.websocket.server.endpoint;