Merge branch 'master' into websocket-stomp

This commit is contained in:
Rossen Stoyanchev
2013-06-27 15:58:12 -04:00
307 changed files with 8375 additions and 4414 deletions

View File

@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket;
import java.nio.ByteBuffer;
/**
* A {@link WebSocketMessage} that contains a binary {@link ByteBuffer} payload.
*
@@ -79,6 +79,7 @@ public final class BinaryMessage extends WebSocketMessage<ByteBuffer> {
}
}
/**
* Returns access to the message payload as a byte array. NOTE: the returned array
* should be considered read-only and should not be modified.

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket;
import org.eclipse.jetty.websocket.api.StatusCode;
@@ -148,8 +149,8 @@ public final class CloseStatus {
/**
* Create a new {@link CloseStatus} instance.
* @param code
* @param reason
* @param code the status code
* @param reason the reason
*/
public CloseStatus(int code, String reason) {
Assert.isTrue((code >= 1000 && code < 5000), "Invalid code");
@@ -157,6 +158,7 @@ public final class CloseStatus {
this.reason = reason;
}
/**
* Returns the status code.
*/

View File

@@ -16,7 +16,6 @@
package org.springframework.web.socket;
/**
* A {@link WebSocketMessage} that contains a textual {@link String} payload.
*
@@ -25,11 +24,9 @@ package org.springframework.web.socket;
*/
public final class TextMessage extends WebSocketMessage<String> {
/**
* Create a new {@link TextMessage} instance.
* @param payload the payload
* @param isLast whether this the last part of a message received or transmitted in parts
*/
public TextMessage(CharSequence payload) {
super(payload.toString(), true);
@@ -44,6 +41,7 @@ public final class TextMessage extends WebSocketMessage<String> {
super(payload.toString(), isLast);
}
@Override
protected int getPayloadSize() {
return getPayload().length();

View File

@@ -19,18 +19,15 @@ package org.springframework.web.socket;
/**
* A handler for WebSocket messages and lifecycle events.
*
* <p>
* Implementations of this interface are encouraged to handle exceptions locally where it
* makes sense or alternatively let the exception bubble up in which case the exception is
* logged and the session closed with {@link CloseStatus#SERVER_ERROR SERVER_ERROR(1011)}
* by default. The exception handling strategy is provided by
* <p>Implementations of this interface are encouraged to handle exceptions locally where
* it makes sense or alternatively let the exception bubble up in which case the exception
* is logged and the session closed with
* {@link CloseStatus#SERVER_ERROR SERVER_ERROR(1011)} by default. The exception handling
* strategy is provided by
* {@link org.springframework.web.socket.support.ExceptionWebSocketHandlerDecorator
* ExceptionWebSocketHandlerDecorator}, which can be customized or replaced by decorating
* the {@link WebSocketHandler} with a different decorator.
*
* @param <T> The type of message being handled {@link TextMessage}, {@link BinaryMessage}
* (or {@link WebSocketMessage} for both).
*
* @author Rossen Stoyanchev
* @author Phillip Webb
* @since 4.0
@@ -40,7 +37,6 @@ public interface WebSocketHandler {
/**
* Invoked after WebSocket negotiation has succeeded and the WebSocket connection is
* opened and ready for use.
*
* @throws Exception this method can handle or propagate exceptions; see class-level
* Javadoc for details.
*/
@@ -48,7 +44,6 @@ public interface WebSocketHandler {
/**
* Invoked when a new WebSocket message arrives.
*
* @throws Exception this method can handle or propagate exceptions; see class-level
* Javadoc for details.
*/
@@ -56,7 +51,6 @@ public interface WebSocketHandler {
/**
* Handle an error from the underlying WebSocket message transport.
*
* @throws Exception this method can handle or propagate exceptions; see class-level
* Javadoc for details.
*/
@@ -67,7 +61,6 @@ public interface WebSocketHandler {
* transport error has occurred. Although the session may technically still be open,
* depending on the underlying implementation, sending messages at this point is
* discouraged and most likely will not succeed.
*
* @throws Exception this method can handle or propagate exceptions; see class-level
* Javadoc for details.
*/

View File

@@ -44,6 +44,7 @@ public abstract class WebSocketMessage<T> {
this.last = isLast;
}
/**
* Returns the message payload. This will never be {@code null}.
*/

View File

@@ -26,7 +26,6 @@ import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
/**
* An abstract base class for implementations of {@link WebSocketSession}.
*

View File

@@ -23,7 +23,6 @@ import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
/**
* A convenient base class for {@link WebSocketHandler} implementation that process binary
* messages only. Text messages are rejected with {@link CloseStatus#NOT_ACCEPTABLE}. All
@@ -35,7 +34,6 @@ import org.springframework.web.socket.WebSocketSession;
*/
public class BinaryWebSocketHandlerAdapter extends WebSocketHandlerAdapter {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
try {

View File

@@ -21,7 +21,6 @@ import java.security.Principal;
import org.springframework.web.socket.WebSocketSession;
/**
* A WebSocketSession with configurable properties.
*

View File

@@ -39,12 +39,12 @@ public class JettyWebSocketListenerAdapter implements WebSocketListener {
private final WebSocketHandler webSocketHandler;
private JettyWebSocketSessionAdapter wsSession;
private final JettyWebSocketSessionAdapter wsSession;
public JettyWebSocketListenerAdapter(WebSocketHandler webSocketHandler, JettyWebSocketSessionAdapter wsSession) {
Assert.notNull(webSocketHandler, "webSocketHandler is required");
Assert.notNull(wsSession, "wsSession is required");
Assert.notNull(webSocketHandler, "webSocketHandler must not be null");
Assert.notNull(wsSession, "wsSession must not be null");
this.webSocketHandler = webSocketHandler;
this.wsSession = wsSession;
}

View File

@@ -29,7 +29,6 @@ import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
/**
* Adapts a Jetty {@link org.eclipse.jetty.websocket.api.Session} to
* {@link WebSocketSession}.
@@ -48,7 +47,7 @@ public class JettyWebSocketSessionAdapter
@Override
public void initSession(Session session) {
Assert.notNull(session, "session is required");
Assert.notNull(session, "session must not be null");
this.session = session;
}
@@ -122,4 +121,4 @@ public class JettyWebSocketSessionAdapter
this.session.close(status.getCode(), status.getReason());
}
}
}

View File

@@ -32,7 +32,6 @@ import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.support.ExceptionWebSocketHandlerDecorator;
/**
* Adapts a {@link WebSocketHandler} to a standard {@link Endpoint}.
*
@@ -49,8 +48,8 @@ public class StandardEndpointAdapter extends Endpoint {
public StandardEndpointAdapter(WebSocketHandler handler, StandardWebSocketSessionAdapter wsSession) {
Assert.notNull(handler, "handler is required");
Assert.notNull(wsSession, "wsSession is required");
Assert.notNull(handler, "handler must not be null");
Assert.notNull(wsSession, "wsSession must not be null");
this.handler = handler;
this.wsSession = wsSession;
}

View File

@@ -48,7 +48,7 @@ public class StandardWebSocketSessionAdapter extends AbstractWebSocketSesssionAd
@Override
public void initSession(javax.websocket.Session session) {
Assert.notNull(session, "session is required");
Assert.notNull(session, "session must not be null");
this.session = session;
}

View File

@@ -23,7 +23,6 @@ import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
/**
* A convenient base class for {@link WebSocketHandler} implementation that process text
* messages only. Binary messages are rejected with {@link CloseStatus#NOT_ACCEPTABLE}. All
@@ -35,7 +34,6 @@ import org.springframework.web.socket.WebSocketSession;
*/
public class TextWebSocketHandlerAdapter extends WebSocketHandlerAdapter {
@Override
protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
try {

View File

@@ -23,7 +23,6 @@ import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
/**
* A convenient base class for {@link WebSocketHandler} implementation with empty methods.
*

View File

@@ -48,18 +48,21 @@ public abstract class ConnectionManagerSupport implements SmartLifecycle {
private int phase = Integer.MAX_VALUE;
private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("EndpointConnectionManager-");
private final TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("EndpointConnectionManager-");
private final Object lifecycleMonitor = new Object();
public ConnectionManagerSupport(String uriTemplate, Object... uriVariables) {
this.uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode().toUri();
this.uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(
uriVariables).encode().toUri();
}
/**
* Set whether to auto-connect to the remote endpoint after this connection manager
* has been initialized and the Spring context has been refreshed.
*
* <p>Default is "false".
*/
public void setAutoStartup(boolean autoStartup) {
@@ -111,8 +114,7 @@ public abstract class ConnectionManagerSupport implements SmartLifecycle {
}
/**
* Connect to the configured {@link #setDefaultUri(URI) default URI}. If already
* connected, the method has no impact.
* Start the websocket connection. If already connected, the method has no impact.
*/
@Override
public final void start() {

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.client;
import java.net.URI;
@@ -25,15 +26,14 @@ import org.springframework.web.socket.WebSocketSession;
* Contract for initiating a WebSocket request. As an alternative considering using the
* declarative style {@link WebSocketConnectionManager} that starts a WebSocket connection
* to a pre-configured URI when the application starts.
*
*
* @author Rossen Stoyanchev
* @since 4.0
*
*
* @see WebSocketConnectionManager
*/
public interface WebSocketClient {
WebSocketSession doHandshake(WebSocketHandler webSocketHandler,
String uriTemplate, Object... uriVariables) throws WebSocketConnectFailureException;

View File

@@ -27,7 +27,6 @@ import org.springframework.core.NestedRuntimeException;
@SuppressWarnings("serial")
public class WebSocketConnectFailureException extends NestedRuntimeException {
public WebSocketConnectFailureException(String msg, Throwable cause) {
super(msg, cause);
}

View File

@@ -57,10 +57,11 @@ public class WebSocketConnectionManager extends ConnectionManagerSupport {
this.syncClientLifecycle = ((client instanceof SmartLifecycle) && !((SmartLifecycle) client).isRunning());
}
/**
* Decorate the WebSocketHandler provided to the class constructor.
* <p>
* By default {@link LoggingWebSocketHandlerDecorator} is added.
*
* <p>By default {@link LoggingWebSocketHandlerDecorator} is added.
*/
protected WebSocketHandler decorateWebSocketHandler(WebSocketHandler handler) {
return new LoggingWebSocketHandlerDecorator(handler);
@@ -88,7 +89,7 @@ public class WebSocketConnectionManager extends ConnectionManagerSupport {
@Override
public void stopInternal() throws Exception {
if (this.syncClientLifecycle) {
((SmartLifecycle) client).stop();
((SmartLifecycle) this.client).stop();
}
super.stopInternal();
}

View File

@@ -61,14 +61,14 @@ public class EndpointConnectionManager extends ConnectionManagerSupport implemen
public EndpointConnectionManager(Endpoint endpoint, String uriTemplate, Object... uriVariables) {
super(uriTemplate, uriVariables);
Assert.notNull(endpoint, "endpoint is required");
Assert.notNull(endpoint, "endpoint must not be null");
this.endpointProvider = null;
this.endpoint = endpoint;
}
public EndpointConnectionManager(Class<? extends Endpoint> endpointClass, String uriTemplate, Object... uriVars) {
super(uriTemplate, uriVars);
Assert.notNull(endpointClass, "endpointClass is required");
Assert.notNull(endpointClass, "endpointClass must not be null");
this.endpointProvider = new BeanCreatingHandlerProvider<Endpoint>(endpointClass);
this.endpoint = null;
}

View File

@@ -45,7 +45,7 @@ import org.springframework.web.util.UriComponentsBuilder;
/**
* Initiates WebSocket requests to a WebSocket server programatically through the standard
* Java WebSocket API .
* Java WebSocket API.
*
* @author Rossen Stoyanchev
* @since 4.0
@@ -62,15 +62,16 @@ public class StandardWebSocketClient implements WebSocketClient {
}
public StandardWebSocketClient(WebSocketContainer webSocketContainer) {
Assert.notNull(webSocketContainer, "webSocketContainer is required");
Assert.notNull(webSocketContainer, "webSocketContainer must not be null");
this.webSocketContainer = webSocketContainer;
}
@Override
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, String uriTemplate, Object... uriVariables)
throws WebSocketConnectFailureException {
Assert.notNull(uriTemplate, "uriTemplate is required");
Assert.notNull(uriTemplate, "uriTemplate must not be null");
UriComponents uriComponents = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode();
return doHandshake(webSocketHandler, null, uriComponents.toUri());
}
@@ -79,8 +80,8 @@ public class StandardWebSocketClient implements WebSocketClient {
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, HttpHeaders httpHeaders, URI uri)
throws WebSocketConnectFailureException {
Assert.notNull(webSocketHandler, "webSocketHandler is required");
Assert.notNull(uri, "uri is required");
Assert.notNull(webSocketHandler, "webSocketHandler must not be null");
Assert.notNull(uri, "uri must not be null");
httpHeaders = (httpHeaders != null) ? httpHeaders : new HttpHeaders();

View File

@@ -32,8 +32,10 @@ import org.springframework.web.socket.client.WebSocketConnectFailureException;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Initiates WebSocket requests to a WebSocket server programatically through the Jetty
* WebSocket API.
*
* @author Rossen Stoyanchev
* @since 4.0
*/
@@ -134,8 +136,8 @@ public class JettyWebSocketClient implements WebSocketClient, SmartLifecycle {
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, HttpHeaders headers, URI uri)
throws WebSocketConnectFailureException {
Assert.notNull(webSocketHandler, "webSocketHandler is required");
Assert.notNull(uri, "uri is required");
Assert.notNull(webSocketHandler, "webSocketHandler must not be null");
Assert.notNull(uri, "uri must not be null");
if (logger.isDebugEnabled()) {
logger.debug("Connecting to " + uri);

View File

@@ -41,8 +41,8 @@ import org.springframework.web.socket.WebSocketHandler;
/**
* A default implemnetation of {@link HandshakeHandler}.
* <p>
* A container-specific {@link RequestUpgradeStrategy} is required since standard Java
*
* <p>A container-specific {@link RequestUpgradeStrategy} is required since standard Java
* WebSocket currently does not provide a way to initiate a WebSocket handshake.
* Currently available are implementations for Tomcat and GlassFish.
*
@@ -57,7 +57,7 @@ public class DefaultHandshakeHandler implements HandshakeHandler {
private List<String> supportedProtocols = new ArrayList<String>();
private RequestUpgradeStrategy requestUpgradeStrategy;
private final RequestUpgradeStrategy requestUpgradeStrategy;
/**

View File

@@ -18,14 +18,13 @@ package org.springframework.web.socket.server;
import org.springframework.core.NestedRuntimeException;
/**
* Thrown when handshake processing failed to complete due to an internal, unrecoverable
* error. This implies a server error (HTTP status code 500) as opposed to a failure in
* the handshake negotiation.
* <p>
* By contrast, when handshake negotiation fails, the response status code will be 200 and
* the response headers and body will have been updated to reflect the cause for the
*
* <p>By contrast, when handshake negotiation fails, the response status code will be 200
* and the response headers and body will have been updated to reflect the cause for the
* failure. A {@link HandshakeHandler} implementation will have protected methods to
* customize updates to the response in those cases.
*
@@ -35,7 +34,6 @@ import org.springframework.core.NestedRuntimeException;
@SuppressWarnings("serial")
public class HandshakeFailureException extends NestedRuntimeException {
public HandshakeFailureException(String msg, Throwable cause) {
super(msg, cause);
}

View File

@@ -33,7 +33,6 @@ import org.springframework.web.socket.support.PerConnectionWebSocketHandler;
*/
public interface HandshakeHandler {
/**
* Initiate the handshake.
*

View File

@@ -43,10 +43,10 @@ import org.springframework.util.ReflectionUtils;
* {@link ServerEndpoint} and registers them as well. Although not required, it is likely
* annotated endpoints should have their {@code configurator} property set to
* {@link SpringConfigurator}.
* <p>
* When this class is used, by declaring it in Spring configuration, it should be possible
* to turn off a Servlet container's scan for WebSocket endpoints. This can be done with
* the help of the {@code <absolute-ordering>} element in web.xml.
*
* <p>When this class is used, by declaring it in Spring configuration, it should be
* possible to turn off a Servlet container's scan for WebSocket endpoints. This can be
* done with the help of the {@code <absolute-ordering>} element in web.xml.
*
* @author Rossen Stoyanchev
* @since 4.0
@@ -123,7 +123,7 @@ public class ServerEndpointExporter implements InitializingBean, BeanPostProcess
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(serverContainer, "javax.websocket.server.ServerContainer not available");
Assert.state(this.serverContainer != null, "javax.websocket.server.ServerContainer not available");
List<Class<?>> allClasses = new ArrayList<Class<?>>(this.annotatedEndpointClasses);
allClasses.addAll(this.annotatedEndpointBeanTypes);

View File

@@ -35,14 +35,13 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.util.Assert;
import org.springframework.web.socket.support.BeanCreatingHandlerProvider;
/**
* An implementation of {@link javax.websocket.server.ServerEndpointConfig} that also
* contains the target {@link javax.websocket.Endpoint}, provided either as a reference or
* as a bean name.
* <p>
* {@link ServerEndpointRegistration} beans are detected by {@link ServerEndpointExporter}
* and registered with a Java WebSocket runtime at startup.
*
* <p>{@link ServerEndpointRegistration} beans are detected by
* {@link ServerEndpointExporter} and registered with a Java WebSocket runtime at startup.
*
* @author Rossen Stoyanchev
* @since 4.0
@@ -67,26 +66,32 @@ public class ServerEndpointRegistration implements ServerEndpointConfig, BeanFac
private final Map<String, Object> userProperties = new HashMap<String, Object>();
private Configurator configurator = new EndpointRegistrationConfigurator();
private final Configurator configurator = new EndpointRegistrationConfigurator();
/**
* Class constructor with the {@code javax.webscoket.Endpoint} class.
*
* @param path
* @param endpointClass
* Create a new {@link ServerEndpointRegistration} instance from an
* {@code javax.webscoket.Endpoint} class.
* @param path the endpoint path
* @param endpointClass the endpoint class
*/
public ServerEndpointRegistration(String path, Class<? extends Endpoint> endpointClass) {
Assert.hasText(path, "path must not be empty");
Assert.notNull(endpointClass, "endpointClass is required");
Assert.notNull(endpointClass, "endpointClass must not be null");
this.path = path;
this.endpointProvider = new BeanCreatingHandlerProvider<Endpoint>(endpointClass);
this.endpoint = null;
}
/**
* Create a new {@link ServerEndpointRegistration} instance from an
* {@code javax.webscoket.Endpoint} instance.
* @param path the endpoint path
* @param endpoint the endpoint instance
*/
public ServerEndpointRegistration(String path, Endpoint endpoint) {
Assert.hasText(path, "path must not be empty");
Assert.notNull(endpoint, "endpoint is required");
Assert.notNull(endpoint, "endpoint must not be null");
this.path = path;
this.endpointProvider = null;
this.endpoint = endpoint;
@@ -188,7 +193,7 @@ 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) getEndpoint();
}
@Override

View File

@@ -33,9 +33,9 @@ import org.springframework.web.socket.sockjs.SockJsService;
* {@code javax.servlet.ServletContext} attribute, simply declaring this FactoryBean and
* using its setters allows configuring the {@code ServerContainer} through Spring
* configuration.
* <p>
* This is useful even if the {@code ServerContainer} is not injected into any other bean.
* For example, an application can configure a {@link DefaultHandshakeHandler}, a
*
* <p>This is useful even if the {@code ServerContainer} is not injected into any other
* bean. For example, an application can configure a {@link DefaultHandshakeHandler}, a
* {@link SockJsService}, or {@link ServerEndpointExporter}, and separately declare this
* FactoryBean in order to customize the properties of the (one and only)
* {@code ServerContainer} instance.
@@ -112,8 +112,8 @@ public class ServletServerContainerFactoryBean
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.serverContainer,
"A ServletContext is required to access the javax.websocket.server.ServerContainer instance");
Assert.state(this.serverContainer != null, "A ServletContext is required to "
+ "access the javax.websocket.server.ServerContainer instance");
if (this.asyncSendTimeout != null) {
this.serverContainer.setAsyncSendTimeout(this.asyncSendTimeout);

View File

@@ -29,6 +29,7 @@ import org.springframework.web.context.WebApplicationContext;
/**
* A {@link javax.websocket.server.ServerEndpointConfig.Configurator} for initializing
* {@link ServerEndpoint}-annotated classes through Spring.
*
* <p>
* <pre class="code">
* &#064;ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class)

View File

@@ -21,7 +21,6 @@ import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.adapter.ConfigurableWebSocketSession;
/**
* Copies information from the handshake HTTP request and response to a given
* {@link WebSocketSession}.
@@ -31,7 +30,6 @@ import org.springframework.web.socket.adapter.ConfigurableWebSocketSession;
*/
public class ServerWebSocketSessionInitializer {
public void initialize(ServerHttpRequest request, ServerHttpResponse response, ConfigurableWebSocketSession session) {
session.setUri(request.getURI());
session.setRemoteHostName(request.getRemoteHostName());

View File

@@ -35,14 +35,15 @@ import org.springframework.web.socket.support.ExceptionWebSocketHandlerDecorator
import org.springframework.web.socket.support.LoggingWebSocketHandlerDecorator;
/**
* An {@link HttpRequestHandler} for processing WebSocket handshake requests.
* <p>
* This is the main class to use when configuring a server WebSocket at a specific URL. It
* is a very thin wrapper around a {@link HandshakeHandler} and a {@link WebSocketHandler}
* instance also adapting the {@link HttpServletRequest} and {@link HttpServletResponse}
* to {@link ServerHttpRequest} and {@link ServerHttpResponse} respectively.
* <p>
* The {@link #decorateWebSocketHandler(WebSocketHandler)} method decorates the given
* A {@link HttpRequestHandler} for processing WebSocket handshake requests.
*
* <p>This is the main class to use when configuring a server WebSocket at a specific URL.
* It is a very thin wrapper around a {@link HandshakeHandler} and a
* {@link WebSocketHandler} instance also adapting the {@link HttpServletRequest} and
* {@link HttpServletResponse} to {@link ServerHttpRequest} and {@link ServerHttpResponse}
* respectively.
*
* <p>The {@link #decorateWebSocketHandler(WebSocketHandler)} method decorates the given
* WebSocketHandler with a logging and exception handling decorators. This method can
* be overridden to change that.
*
@@ -61,16 +62,17 @@ public class WebSocketHttpRequestHandler implements HttpRequestHandler {
}
public WebSocketHttpRequestHandler( WebSocketHandler webSocketHandler, HandshakeHandler handshakeHandler) {
Assert.notNull(webSocketHandler, "webSocketHandler is required");
Assert.notNull(handshakeHandler, "handshakeHandler is required");
Assert.notNull(webSocketHandler, "webSocketHandler must not be null");
Assert.notNull(handshakeHandler, "handshakeHandler must not be null");
this.webSocketHandler = decorateWebSocketHandler(webSocketHandler);
this.handshakeHandler = new DefaultHandshakeHandler();
}
/**
* Decorate the WebSocketHandler provided to the class constructor.
* <p>
* By default {@link ExceptionWebSocketHandlerDecorator} and
*
* <p>By default {@link ExceptionWebSocketHandlerDecorator} and
* {@link LoggingWebSocketHandlerDecorator} are applied are added.
*/
protected WebSocketHandler decorateWebSocketHandler(WebSocketHandler handler) {

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs;
import java.io.IOException;
@@ -27,6 +28,7 @@ import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -48,8 +50,8 @@ import org.springframework.web.socket.WebSocketHandler;
* support, SockJS path resolution, and processing for static SockJS requests (e.g.
* "/info", "/iframe.html", etc). Sub-classes are responsible for handling transport
* requests.
* <p>
* It is expected that this service is mapped correctly to one or more prefixes such as
*
* <p>It is expected that this service is mapped correctly to one or more prefixes such as
* "/echo" including all sub-URLs (e.g. "/echo/**"). A SockJS service itself is generally
* unaware of request mapping details but nevertheless must be able to extract the SockJS
* path, which is the portion of the request path following the prefix. In most cases,
@@ -63,7 +65,7 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf
protected final Log logger = LogFactory.getLog(getClass());
private static final int ONE_YEAR = 365 * 24 * 60 * 60;
private static final long ONE_YEAR = TimeUnit.DAYS.toSeconds(365);
private String name = "SockJSService@" + ObjectUtils.getIdentityHexString(this);
@@ -88,10 +90,11 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf
public AbstractSockJsService(TaskScheduler scheduler) {
Assert.notNull(scheduler, "scheduler is required");
Assert.notNull(scheduler, "scheduler must not be null");
this.taskScheduler = scheduler;
}
/**
* A unique name for the service mainly for logging purposes.
*/
@@ -107,8 +110,8 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf
* Use this property to configure one or more prefixes that this SockJS service is
* allowed to serve. The prefix (e.g. "/echo") is needed to extract the SockJS
* specific portion of the URL (e.g. "${prefix}/info", "${prefix}/iframe.html", etc).
* <p>
* This property is not strictly required. In most cases, the SockJS path can be
*
* <p>This property is not strictly required. In most cases, the SockJS path can be
* auto-detected since the initial request from the SockJS client is of the form
* "{prefix}/info". Assuming the SockJS service is mapped correctly (e.g. using
* Ant-style pattern "/echo/**") this should work fine. This property can be used
@@ -144,8 +147,8 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf
* a domain local to the SockJS server. The iframe does need to load the
* SockJS javascript client library and this option allows configuring its
* url.
* <p>
* By default this is set to point to
*
* <p>By default this is set to point to
* "https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js".
*/
public AbstractSockJsService setSockJsClientLibraryUrl(String clientLibraryUrl) {
@@ -168,15 +171,15 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf
@Override
public int getStreamBytesLimit() {
return streamBytesLimit;
return this.streamBytesLimit;
}
/**
* Some load balancers do sticky sessions, but only if there is a JSESSIONID
* cookie. Even if it is set to a dummy value, it doesn't matter since
* session information is added by the load balancer.
* <p>
* Set this option to indicate if a JSESSIONID cookie should be created. The
*
* <p>Set this option to indicate if a JSESSIONID cookie should be created. The
* default value is "true".
*/
public AbstractSockJsService setJsessionIdCookieRequired(boolean jsessionIdCookieRequired) {
@@ -211,8 +214,8 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf
* The amount of time in milliseconds before a client is considered
* disconnected after not having a receiving connection, i.e. an active
* connection over which the server can send data to the client.
* <p>
* The default value is 5000.
*
* <p>The default value is 5000.
*/
public void setDisconnectDelay(long disconnectDelay) {
this.disconnectDelay = disconnectDelay;
@@ -228,8 +231,8 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf
/**
* Some load balancers don't support websockets. This option can be used to
* disable the WebSocket transport on the server side.
* <p>
* The default value is "true".
*
* <p>The default value is "true".
*/
public void setWebSocketsEnabled(boolean webSocketsEnabled) {
this.webSocketsEnabled = webSocketsEnabled;
@@ -245,12 +248,6 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf
/**
* TODO
*
* @param request
* @param response
* @param sockJsPath
*
* @throws Exception
*/
@Override
public final void handleRequest(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler)
@@ -441,6 +438,7 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf
void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException;
}
private static final Random random = new Random();
private final SockJsRequestHandler infoHandler = new SockJsRequestHandler() {

View File

@@ -34,7 +34,6 @@ import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.adapter.ConfigurableWebSocketSession;
/**
* An abstract base class SockJS sessions implementing {@link WebSocketSession}.
*
@@ -58,24 +57,26 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess
private final SockJsConfiguration sockJsConfig;
private WebSocketHandler handler;
private final WebSocketHandler handler;
private State state = State.NEW;
private long timeCreated = System.currentTimeMillis();
private final long timeCreated = System.currentTimeMillis();
private long timeLastActive = timeCreated;
private long timeLastActive = this.timeCreated;
private ScheduledFuture<?> heartbeatTask;
/**
* @param sessionId
* @param sessionId the session ID
* @param config the sockJS configuration
* @param webSocketHandler the recipient of SockJS messages
*/
public AbstractSockJsSession(String sessionId, SockJsConfiguration config, WebSocketHandler webSocketHandler) {
Assert.notNull(sessionId, "sessionId is required");
Assert.notNull(webSocketHandler, "webSocketHandler is required");
public AbstractSockJsSession(String sessionId, SockJsConfiguration config,
WebSocketHandler webSocketHandler) {
Assert.notNull(sessionId, "sessionId must not be null");
Assert.notNull(webSocketHandler, "webSocketHandler must not be null");
this.id = sessionId;
this.handler = webSocketHandler;
this.sockJsConfig = config;
@@ -191,7 +192,7 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess
/**
* Invoked in reaction to the underlying connection being closed by the remote side
* (or the WebSocket container) in order to perform cleanup and notify the
* {@link TextMessageHandler}. This is in contrast to {@link #close()} that pro-actively
* {@link WebSocketHandler}. This is in contrast to {@link #close()} that pro-actively
* closes the connection.
*/
public final void delegateConnectionClosed(CloseStatus status) throws Exception {
@@ -224,7 +225,8 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess
/**
* {@inheritDoc}
* <p>Performs cleanup and notifies the {@link SockJsHandler}.
*
* <p>Performs cleanup and notifies the {@link WebSocketHandler}.
*/
@Override
public final void close() throws IOException {
@@ -233,7 +235,8 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess
/**
* {@inheritDoc}
* <p>Performs cleanup and notifies the {@link SockJsHandler}.
*
* <p>Performs cleanup and notifies the {@link WebSocketHandler}.
*/
@Override
public final void close(CloseStatus status) throws IOException {
@@ -329,7 +332,7 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess
}
protected void scheduleHeartbeat() {
Assert.notNull(this.sockJsConfig.getTaskScheduler(), "heartbeatScheduler not configured");
Assert.state(this.sockJsConfig.getTaskScheduler() != null, "heartbeatScheduler not configured");
cancelHeartbeat();
if (!isActive()) {
return;

View File

@@ -35,8 +35,8 @@ public interface SockJsConfiguration {
* closed. After that client will open a new request. Setting this value to
* one effectively disables streaming and will make streaming transports to
* behave like polling transports.
* <p>
* The default value is 128K (i.e. 128 * 1024).
*
* <p>The default value is 128K (i.e. 128 * 1024).
*/
public int getStreamBytesLimit();
@@ -44,8 +44,8 @@ public interface SockJsConfiguration {
* The amount of time in milliseconds when the server has not sent any
* messages and after which the server should send a heartbeat frame to the
* client in order to keep the connection from breaking.
* <p>
* The default value is 25,000 (25 seconds).
*
* <p>The default value is 25,000 (25 seconds).
*/
public long getHeartbeatTime();

View File

@@ -44,7 +44,7 @@ public class SockJsFrame {
private SockJsFrame(String content) {
Assert.notNull("content is required");
Assert.notNull("content must not be null");
this.content = content;
}
@@ -144,7 +144,7 @@ public class SockJsFrame {
}
public static String prepareContent(String... messages) {
Assert.notNull(messages, "messages required");
Assert.notNull(messages, "messages must not be null");
StringBuilder sb = new StringBuilder();
sb.append("a[");
for (int i=0; i < messages.length; i++) {
@@ -172,14 +172,12 @@ public class SockJsFrame {
private final String format;
public DefaultFrameFormat(String format) {
Assert.notNull(format, "format is required");
Assert.notNull(format, "format must not be null");
this.format = format;
}
/**
*
* @param format a String with a single %s formatting character where the
* frame content is to be inserted; e.g. "data: %s\r\n\r\n"
* @param frame the SockJs frame.
* @return new SockJsFrame instance with the formatted content
*/
@Override

View File

@@ -32,7 +32,6 @@ import org.springframework.web.socket.WebSocketHandler;
*/
public interface SockJsService {
void handleRequest(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler)
throws IOException, TransportErrorException;

View File

@@ -22,7 +22,6 @@ import org.springframework.web.socket.WebSocketHandler;
* A factory for creating a SockJS session. {@link TransportHandler}s typically also serve
* as SockJS session factories.
*
* @param <S> The type of session being created
* @author Rossen Stoyanchev
* @since 4.0
*/

View File

@@ -19,15 +19,14 @@ package org.springframework.web.socket.sockjs;
import org.springframework.core.NestedRuntimeException;
import org.springframework.web.socket.WebSocketHandler;
/**
* Raised when a TransportHandler fails during request processing.
* <p>
* If the underlying exception occurs while sending messages to the client, the session is
* closed and the {@link WebSocketHandler} notified.
* <p>
* If the underlying exception occurs while processing an incoming HTTP request, including
* over HTTP POST, the session will remain open. Only the incoming request is rejected.
* Raised when a TransportHandler fails during request processing. If the underlying
* exception occurs while sending messages to the client, the session is closed and the
* {@link WebSocketHandler} notified.
*
* <p>If the underlying exception occurs while processing an incoming HTTP request,
* including over HTTP POST, the session will remain open. Only the incoming request is
* rejected.
*
* @author Rossen Stoyanchev
* @since 4.0
@@ -43,7 +42,7 @@ public class TransportErrorException extends NestedRuntimeException {
}
public String getSockJsSessionId() {
return sockJsSessionId;
return this.sockJsSessionId;
}
@Override

View File

@@ -17,6 +17,7 @@
package org.springframework.web.socket.sockjs;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -54,12 +55,13 @@ public enum TransportType {
private final List<String> headerHints;
private static final Map<String, TransportType> transportTypes = new HashMap<String, TransportType>();
private static final Map<String, TransportType> TRANSPORT_TYPES;
static {
Map<String, TransportType> transportTypes = new HashMap<String, TransportType>();
for (TransportType type : values()) {
transportTypes.put(type.value, type);
}
TRANSPORT_TYPES = Collections.unmodifiableMap(transportTypes);
}
@@ -94,7 +96,7 @@ public enum TransportType {
}
public static TransportType fromValue(String value) {
return transportTypes.get(value);
return TRANSPORT_TYPES.get(value);
}
@Override

View File

@@ -120,6 +120,7 @@ public class DefaultSockJsService extends AbstractSockJsService {
}
}
protected final Set<TransportHandler> getDefaultTransportHandlers() {
Set<TransportHandler> result = new HashSet<TransportHandler>();
result.add(new XhrPollingTransportHandler());

View File

@@ -34,14 +34,13 @@ import org.springframework.web.socket.support.ExceptionWebSocketHandlerDecorator
import org.springframework.web.socket.support.LoggingWebSocketHandlerDecorator;
/**
* An {@link HttpRequestHandler} for processing SockJS requests.
* <p>
* This is the main class to use when configuring a SockJS service at a specific URL. It
* is a very thin wrapper around a {@link SockJsService} and a {@link WebSocketHandler}
* instance also adapting the {@link HttpServletRequest} and {@link HttpServletResponse}
* to {@link ServerHttpRequest} and {@link ServerHttpResponse} respectively.
* <p>
* The {@link #decorateWebSocketHandler(WebSocketHandler)} method decorates the given
* An {@link HttpRequestHandler} for processing SockJS requests. This is the main class
* to use when configuring a SockJS service at a specific URL. It is a very thin wrapper
* around a {@link SockJsService} and a {@link WebSocketHandler} instance also adapting
* the {@link HttpServletRequest} and {@link HttpServletResponse} to
* {@link ServerHttpRequest} and {@link ServerHttpResponse} respectively.
*
* <p>The {@link #decorateWebSocketHandler(WebSocketHandler)} method decorates the given
* WebSocketHandler with a logging and exception handling decorators. This method can be
* overridden to change that.
*
@@ -56,19 +55,22 @@ public class SockJsHttpRequestHandler implements HttpRequestHandler {
/**
* Class constructor with {@link SockJsHandler} instance ...
* Create a new {@link SockJsHttpRequestHandler}.
* @param sockJsService the SockJS service
* @param webSocketHandler the websocket handler
*/
public SockJsHttpRequestHandler(SockJsService sockJsService, WebSocketHandler webSocketHandler) {
Assert.notNull(sockJsService, "sockJsService is required");
Assert.notNull(webSocketHandler, "webSocketHandler is required");
Assert.notNull(sockJsService, "sockJsService must not be null");
Assert.notNull(webSocketHandler, "webSocketHandler must not be null");
this.sockJsService = sockJsService;
this.webSocketHandler = decorateWebSocketHandler(webSocketHandler);
}
/**
* Decorate the WebSocketHandler provided to the class constructor.
* <p>
* By default {@link ExceptionWebSocketHandlerDecorator} and
*
* <p>By default {@link ExceptionWebSocketHandlerDecorator} and
* {@link LoggingWebSocketHandlerDecorator} are applied are added.
*/
protected WebSocketHandler decorateWebSocketHandler(WebSocketHandler handler) {

View File

@@ -54,6 +54,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
super(sessionId, config, handler);
}
public synchronized void setInitialRequest(ServerHttpRequest request, ServerHttpResponse response,
FrameFormat frameFormat) throws TransportErrorException {

View File

@@ -48,7 +48,7 @@ public class EventSourceTransportHandler extends AbstractHttpSendingTransportHan
@Override
public StreamingSockJsSession createSession(String sessionId, WebSocketHandler handler) {
Assert.notNull(getSockJsConfig(), "This transport requires SockJsConfiguration");
Assert.state(getSockJsConfig() != null, "This transport requires SockJsConfiguration");
return new StreamingSockJsSession(sessionId, getSockJsConfig(), handler) {
@Override
protected void writePrelude() throws IOException {

View File

@@ -45,6 +45,10 @@ public class HtmlFileTransportHandler extends AbstractHttpSendingTransportHandle
private static final String PARTIAL_HTML_CONTENT;
// Safari needs at least 1024 bytes to parse the website.
// http://code.google.com/p/browsersec/wiki/Part2#Survey_of_content_sniffing_behaviors
private static final int MINIMUM_PARTIAL_HTML_CONTENT_LENGTH = 1024;
static {
StringBuilder sb = new StringBuilder(
"<!doctype html>\n" +
@@ -61,11 +65,8 @@ public class HtmlFileTransportHandler extends AbstractHttpSendingTransportHandle
" </script>"
);
// Safari needs at least 1024 bytes to parse the website.
// http://code.google.com/p/browsersec/wiki/Part2#Survey_of_content_sniffing_behaviors
int spaces = 1024 - sb.length();
for (int i=0; i < spaces; i++) {
sb.append(' ');
while(sb.length() < MINIMUM_PARTIAL_HTML_CONTENT_LENGTH) {
sb.append(" ");
}
PARTIAL_HTML_CONTENT = sb.toString();
@@ -84,7 +85,7 @@ public class HtmlFileTransportHandler extends AbstractHttpSendingTransportHandle
@Override
public StreamingSockJsSession createSession(String sessionId, WebSocketHandler handler) {
Assert.notNull(getSockJsConfig(), "This transport requires SockJsConfiguration");
Assert.state(getSockJsConfig() != null, "This transport requires SockJsConfiguration");
return new StreamingSockJsSession(sessionId, getSockJsConfig(), handler) {

View File

@@ -51,7 +51,7 @@ public class JsonpPollingTransportHandler extends AbstractHttpSendingTransportHa
@Override
public PollingSockJsSession createSession(String sessionId, WebSocketHandler handler) {
Assert.notNull(getSockJsConfig(), "This transport requires SockJsConfiguration");
Assert.state(getSockJsConfig() != null, "This transport requires SockJsConfiguration");
return new PollingSockJsSession(sessionId, getSockJsConfig(), handler);
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs.transport;
import java.io.IOException;
@@ -32,6 +33,7 @@ public class PollingSockJsSession extends AbstractHttpSockJsSession {
super(sessionId, config, handler);
}
@Override
protected void flushCache() throws IOException {
cancelHeartbeat();

View File

@@ -26,13 +26,12 @@ import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.adapter.TextWebSocketHandlerAdapter;
import org.springframework.web.socket.sockjs.SockJsConfiguration;
/**
* An implementation of {@link WebSocketHandler} that adds SockJS messages frames, sends
* SockJS heartbeat messages, and delegates lifecycle events and messages to a target
* {@link WebSocketHandler}.
* <p>
* Methods in this class allow exceptions from the wrapped {@link WebSocketHandler} to
*
* <p>Methods in this class allow exceptions from the wrapped {@link WebSocketHandler} to
* propagate. However, any exceptions resulting from SockJS message handling (e.g. while
* sending SockJS frames or heartbeat messages) are caught and treated as transport
* errors, i.e. routed to the
@@ -46,7 +45,7 @@ public class SockJsWebSocketHandler extends TextWebSocketHandlerAdapter {
private final SockJsConfiguration sockJsConfig;
private WebSocketServerSockJsSession session;
private final WebSocketServerSockJsSession session;
private final AtomicInteger sessionCount = new AtomicInteger(0);
@@ -54,9 +53,9 @@ public class SockJsWebSocketHandler extends TextWebSocketHandlerAdapter {
public SockJsWebSocketHandler(SockJsConfiguration config,
WebSocketHandler webSocketHandler, WebSocketServerSockJsSession session) {
Assert.notNull(config, "sockJsConfig is required");
Assert.notNull(webSocketHandler, "webSocketHandler is required");
Assert.notNull(session, "session is required");
Assert.notNull(config, "config must not be null");
Assert.notNull(webSocketHandler, "webSocketHandler must not be null");
Assert.notNull(session, "session must not be null");
this.sockJsConfig = config;
this.session = session;

View File

@@ -29,7 +29,6 @@ import org.springframework.web.socket.sockjs.SockJsFrame;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* A SockJS session for use with the WebSocket transport.
*
@@ -48,6 +47,7 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession {
super(sessionId, config, handler);
}
public void initWebSocketSession(WebSocketSession session) throws Exception {
this.webSocketSession = session;
try {
@@ -75,7 +75,7 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession {
}
String[] messages;
try {
messages = objectMapper.readValue(payload, String[].class);
messages = this.objectMapper.readValue(payload, String[].class);
}
catch (IOException ex) {
logger.error("Broken data received. Terminating WebSocket connection abruptly", ex);

View File

@@ -31,12 +31,11 @@ import org.springframework.web.socket.sockjs.TransportErrorException;
import org.springframework.web.socket.sockjs.TransportHandler;
import org.springframework.web.socket.sockjs.TransportType;
/**
* A WebSocket {@link TransportHandler}. Uses {@link SockJsWebSocketHandler} and
* {@link WebSocketServerSockJsSession} to add SockJS processing.
* <p>
* Also implements {@link HandshakeHandler} to support raw WebSocket communication at
*
* <p>Also implements {@link HandshakeHandler} to support raw WebSocket communication at
* SockJS URL "/websocket".
*
* @author Rossen Stoyanchev
@@ -51,10 +50,11 @@ public class WebSocketTransportHandler implements ConfigurableTransportHandler,
public WebSocketTransportHandler(HandshakeHandler handshakeHandler) {
Assert.notNull(handshakeHandler, "handshakeHandler is required");
Assert.notNull(handshakeHandler, "handshakeHandler must not be null");
this.handshakeHandler = handshakeHandler;
}
@Override
public TransportType getTransportType() {
return TransportType.WEBSOCKET;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs.transport;
import java.nio.charset.Charset;
@@ -26,7 +27,6 @@ import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat;
import org.springframework.web.socket.sockjs.TransportHandler;
import org.springframework.web.socket.sockjs.TransportType;
/**
* A {@link TransportHandler} based on XHR (long) polling.
*
@@ -35,7 +35,6 @@ import org.springframework.web.socket.sockjs.TransportType;
*/
public class XhrPollingTransportHandler extends AbstractHttpSendingTransportHandler {
@Override
public TransportType getTransportType() {
return TransportType.XHR;
@@ -53,7 +52,7 @@ public class XhrPollingTransportHandler extends AbstractHttpSendingTransportHand
@Override
public PollingSockJsSession createSession(String sessionId, WebSocketHandler handler) {
Assert.notNull(getSockJsConfig(), "This transport requires SockJsConfiguration");
Assert.state(getSockJsConfig() != null, "This transport requires SockJsConfiguration");
return new PollingSockJsSession(sessionId, getSockJsConfig(), handler);
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs.transport;
import java.io.IOException;
@@ -27,7 +28,6 @@ import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat;
import org.springframework.web.socket.sockjs.TransportHandler;
import org.springframework.web.socket.sockjs.TransportType;
/**
* A {@link TransportHandler} that sends messages over an HTTP streaming request.
*
@@ -36,7 +36,6 @@ import org.springframework.web.socket.sockjs.TransportType;
*/
public class XhrStreamingTransportHandler extends AbstractHttpSendingTransportHandler {
@Override
public TransportType getTransportType() {
return TransportType.XHR_STREAMING;
@@ -49,7 +48,7 @@ public class XhrStreamingTransportHandler extends AbstractHttpSendingTransportHa
@Override
public StreamingSockJsSession createSession(String sessionId, WebSocketHandler handler) {
Assert.notNull(getSockJsConfig(), "This transport requires SockJsConfiguration");
Assert.state(getSockJsConfig() != null, "This transport requires SockJsConfiguration");
return new StreamingSockJsSession(sessionId, getSockJsConfig(), handler) {

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs.transport;
import java.io.IOException;
@@ -22,7 +23,6 @@ import org.springframework.http.server.ServerHttpRequest;
import org.springframework.web.socket.sockjs.TransportHandler;
import org.springframework.web.socket.sockjs.TransportType;
/**
* A {@link TransportHandler} that receives messages over HTTP.
*
@@ -30,7 +30,6 @@ import org.springframework.web.socket.sockjs.TransportType;
*/
public class XhrTransportHandler extends AbstractHttpReceivingTransportHandler {
@Override
public TransportType getTransportType() {
return TransportType.XHR_SEND;

View File

@@ -18,9 +18,8 @@
* Server-side support for SockJS transports including
* {@link org.springframework.web.socket.sockjs.TransportHandler} implementations
* for processing incoming requests and their
* {@link org.springframework.sockjs.SockJsSession} counterparts for
* {@link org.springframework.web.socket.sockjs.AbstractSockJsSession session} counterparts for
* sending messages over the various transports.
*
*/
package org.springframework.web.socket.sockjs.transport;

View File

@@ -29,7 +29,7 @@ import org.springframework.util.Assert;
* Instantiates a target handler through a Spring {@link BeanFactory} and also provides
* an equivalent destroy method. Mainly for internal use to assist with initializing and
* destroying handlers with per-connection lifecycle.
*
*
* @author Rossen Stoyanchev
* @since 4.0
*/
@@ -43,7 +43,7 @@ public class BeanCreatingHandlerProvider<T> implements BeanFactoryAware {
public BeanCreatingHandlerProvider(Class<? extends T> handlerType) {
Assert.notNull(handlerType, "handlerType is required");
Assert.notNull(handlerType, "handlerType must not be null");
this.handlerType = handlerType;
}
@@ -83,7 +83,7 @@ public class BeanCreatingHandlerProvider<T> implements BeanFactoryAware {
@Override
public String toString() {
return "BeanCreatingHandlerProvider [handlerClass=" + handlerType + "]";
return "BeanCreatingHandlerProvider [handlerClass=" + this.handlerType + "]";
}
}

View File

@@ -23,7 +23,6 @@ import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
/**
* An exception handling {@link WebSocketHandlerDecorator}. Traps all {@link Throwable}
* instances that escape from the decorated handler and closes the session with
@@ -34,13 +33,14 @@ import org.springframework.web.socket.WebSocketSession;
*/
public class ExceptionWebSocketHandlerDecorator extends WebSocketHandlerDecorator {
private Log logger = LogFactory.getLog(ExceptionWebSocketHandlerDecorator.class);
private final Log logger = LogFactory.getLog(ExceptionWebSocketHandlerDecorator.class);
public ExceptionWebSocketHandlerDecorator(WebSocketHandler delegate) {
super(delegate);
}
@Override
public void afterConnectionEstablished(WebSocketSession session) {
try {

View File

@@ -23,7 +23,6 @@ import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
/**
* A {@link WebSocketHandlerDecorator} that adds logging to WebSocket lifecycle events.
*
@@ -32,7 +31,7 @@ import org.springframework.web.socket.WebSocketSession;
*/
public class LoggingWebSocketHandlerDecorator extends WebSocketHandlerDecorator {
private Log logger = LogFactory.getLog(LoggingWebSocketHandlerDecorator.class);
private final Log logger = LogFactory.getLog(LoggingWebSocketHandlerDecorator.class);
public LoggingWebSocketHandlerDecorator(WebSocketHandler delegate) {

View File

@@ -22,7 +22,6 @@ import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
/**
* @author Rossen Stoyanchev
* @since 4.0
@@ -33,7 +32,7 @@ public class WebSocketHandlerDecorator implements WebSocketHandler {
public WebSocketHandlerDecorator(WebSocketHandler delegate) {
Assert.notNull(delegate, "delegate is required");
Assert.notNull(delegate, "delegate must not be null");
this.delegate = delegate;
}
@@ -42,6 +41,14 @@ public class WebSocketHandlerDecorator implements WebSocketHandler {
return this.delegate;
}
public WebSocketHandler getLastHandler() {
WebSocketHandler result = this.delegate;
while (result instanceof WebSocketHandlerDecorator) {
result = ((WebSocketHandlerDecorator) result).getDelegate();
}
return result;
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
this.delegate.afterConnectionEstablished(session);
@@ -67,7 +74,6 @@ public class WebSocketHandlerDecorator implements WebSocketHandler {
return this.delegate.supportsPartialMessages();
}
@Override
public String toString() {
return getClass().getSimpleName() + " [delegate=" + this.delegate + "]";