Add EndpointRequestUpgradeStrategy

Now there is just one EndpointHandshakeRequestHandler that works on
different runtimes.
This commit is contained in:
Rossen Stoyanchev 2013-03-28 12:03:33 -04:00
parent 741927664c
commit 30ab5953f9
8 changed files with 197 additions and 94 deletions

View File

@ -33,12 +33,14 @@ import org.springframework.util.Assert;
* Java WebSocket runtime and also configures the underlying
* {@link javax.websocket.server.ServerContainer}.
*
* <p>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;

View File

@ -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);
}
}

View File

@ -46,13 +46,13 @@ import org.springframework.websocket.endpoint.StandardWebSocketHandlerAdapter;
* which case it will be adapted via {@link StandardWebSocketHandlerAdapter}.
*
* <p>
* 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> T getEndpointInstance(Class<T> 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<String> supported, List<String> requested) {
return ServerEndpointRegistration.this.selectSubProtocol(requested);
return EndpointRegistration.this.selectSubProtocol(requested);
}
@Override
public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested) {
return ServerEndpointRegistration.this.selectExtensions(requested);
return EndpointRegistration.this.selectExtensions(requested);
}
};
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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.<String, String> emptyMap(), servletRequest.isSecure());
}
}

View File

@ -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.<String, String> emptyMap(), servletRequest.isSecure());
}
}

View File

@ -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;