diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java b/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java index d8565455c1..24c5e84cbb 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java @@ -139,7 +139,7 @@ public abstract class AbstractSockJsSession implements WebSocketSession { } } - public void delegateError(Throwable ex) { + public void delegateError(Throwable ex) throws Exception { this.handler.handleError(ex, this); } diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/server/support/DefaultSockJsService.java b/spring-websocket/src/main/java/org/springframework/sockjs/server/support/DefaultSockJsService.java index 5a4baadf3f..3d389353e9 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/server/support/DefaultSockJsService.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/server/support/DefaultSockJsService.java @@ -36,6 +36,7 @@ import org.springframework.sockjs.AbstractSockJsSession; import org.springframework.sockjs.SockJsSessionFactory; import org.springframework.sockjs.server.AbstractSockJsService; import org.springframework.sockjs.server.ConfigurableTransportHandler; +import org.springframework.sockjs.server.SockJsService; import org.springframework.sockjs.server.TransportHandler; import org.springframework.sockjs.server.TransportType; import org.springframework.sockjs.server.transport.EventSourceTransportHandler; @@ -54,7 +55,8 @@ import org.springframework.websocket.server.HandshakeHandler; /** - * TODO + * A default implementation of {@link SockJsService} adding support for transport handling + * and session management. * * @author Rossen Stoyanchev * @since 4.0 @@ -68,10 +70,31 @@ public class DefaultSockJsService extends AbstractSockJsService { private ScheduledFuture sessionCleanupTask; + /** + * Create an instance with default {@link TransportHandler transport handler} types. + * + * @param taskScheduler a task scheduler for heart-beat messages and removing + * timed-out sessions; the provided TaskScheduler should be declared as a + * Spring bean to ensure it is initialized at start up and shut down when the + * application stops. + */ public DefaultSockJsService(TaskScheduler taskScheduler) { this(taskScheduler, null); } + /** + * Create an instance by overriding or replacing completely the default + * {@link TransportHandler transport handler} types. + * + * @param taskScheduler a task scheduler for heart-beat messages and removing + * timed-out sessions; the provided TaskScheduler should be declared as a + * Spring bean to ensure it is initialized at start up and shut down when the + * application stops. + * @param transportHandlers the transport handlers to use (replaces the default ones); + * can be {@code null}. + * @param transportHandlerOverrides zero or more overrides to the default transport + * handler types. + */ public DefaultSockJsService(TaskScheduler taskScheduler, Set transportHandlers, TransportHandler... transportHandlerOverrides) { @@ -82,7 +105,7 @@ public class DefaultSockJsService extends AbstractSockJsService { addTransportHandlers(Arrays.asList(transportHandlerOverrides)); } - protected Set getDefaultTransportHandlers() { + protected final Set getDefaultTransportHandlers() { Set result = new HashSet(); result.add(new XhrPollingTransportHandler()); result.add(new XhrTransportHandler()); @@ -91,14 +114,12 @@ public class DefaultSockJsService extends AbstractSockJsService { result.add(new XhrStreamingTransportHandler()); result.add(new EventSourceTransportHandler()); result.add(new HtmlFileTransportHandler()); - if (isWebSocketEnabled()) { - try { - result.add(new WebSocketTransportHandler(new DefaultHandshakeHandler())); - } - catch (Exception ex) { - if (logger.isWarnEnabled()) { - logger.warn("Failed to add default WebSocketTransportHandler: " + ex.getMessage()); - } + try { + result.add(new WebSocketTransportHandler(new DefaultHandshakeHandler())); + } + catch (Exception ex) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to add default WebSocketTransportHandler: " + ex.getMessage()); } } return result; diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/SockJsWebSocketHandler.java b/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/SockJsWebSocketHandler.java index eef056aab1..07b6cf3457 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/SockJsWebSocketHandler.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/SockJsWebSocketHandler.java @@ -102,7 +102,7 @@ public class SockJsWebSocketHandler implements TextMessageHandler { } @Override - public void handleError(Throwable exception, WebSocketSession webSocketSession) { + public void handleError(Throwable exception, WebSocketSession webSocketSession) throws Exception { this.session.delegateError(exception); } diff --git a/spring-websocket/src/main/java/org/springframework/websocket/CloseStatus.java b/spring-websocket/src/main/java/org/springframework/websocket/CloseStatus.java index 979ec4090f..b0f751392d 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/CloseStatus.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/CloseStatus.java @@ -113,19 +113,15 @@ public final class CloseStatus { public static final CloseStatus SERVER_ERROR = new CloseStatus(1011); /** - * 1012 indicates that the service is restarted. A client may reconnect, and if it - * choses to do, should reconnect using a randomized delay of 5 - 30s. - *

See - * [hybi] Additional WebSocket Close Error Codes + * "1012 indicates that the service is restarted. A client may reconnect, and if it + * chooses to do, should reconnect using a randomized delay of 5 - 30s." */ public static final CloseStatus SERVICE_RESTARTED = new CloseStatus(1012); /** - * 1013 indicates that the service is experiencing overload. A client should only + * "1013 indicates that the service is experiencing overload. A client should only * connect to a different IP (when there are multiple for the target) or reconnect to - * the same IP upon user action. - *

See - * [hybi] Additional WebSocket Close Error Codes + * the same IP upon user action." */ public static final CloseStatus SERVICE_OVERLOAD = new CloseStatus(1013); diff --git a/spring-websocket/src/main/java/org/springframework/websocket/WebSocketHandler.java b/spring-websocket/src/main/java/org/springframework/websocket/WebSocketHandler.java index b420e83940..a4972eeb46 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/WebSocketHandler.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/WebSocketHandler.java @@ -39,6 +39,6 @@ public interface WebSocketHandler { /** * TODO */ - void handleError(Throwable exception, WebSocketSession session); + void handleError(Throwable exception, WebSocketSession session) throws Exception; } diff --git a/spring-websocket/src/main/java/org/springframework/websocket/client/WebSocketClient.java b/spring-websocket/src/main/java/org/springframework/websocket/client/WebSocketClient.java index 579fcb1d8a..169170da8d 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/client/WebSocketClient.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/client/WebSocketClient.java @@ -37,6 +37,9 @@ import org.springframework.websocket.WebSocketSession; public interface WebSocketClient { + WebSocketSession doHandshake(WebSocketHandler handler, + String uriTemplate, Object... uriVariables) throws WebSocketConnectFailureException; + WebSocketSession doHandshake(HandlerProvider handler, String uriTemplate, Object... uriVariables) throws WebSocketConnectFailureException; diff --git a/spring-websocket/src/main/java/org/springframework/websocket/client/endpoint/StandardWebSocketClient.java b/spring-websocket/src/main/java/org/springframework/websocket/client/endpoint/StandardWebSocketClient.java index 1a15d4bd95..97655d29e9 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/client/endpoint/StandardWebSocketClient.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/client/endpoint/StandardWebSocketClient.java @@ -38,6 +38,7 @@ import org.springframework.websocket.client.WebSocketClient; import org.springframework.websocket.client.WebSocketConnectFailureException; import org.springframework.websocket.endpoint.StandardWebSocketSession; import org.springframework.websocket.endpoint.WebSocketHandlerEndpoint; +import org.springframework.websocket.support.SimpleHandlerProvider; /** @@ -59,6 +60,13 @@ public class StandardWebSocketClient implements WebSocketClient { this.webSocketContainer = container; } + @Override + public WebSocketSession doHandshake(WebSocketHandler handler, String uriTemplate, Object... uriVariables) + throws WebSocketConnectFailureException { + + return doHandshake(new SimpleHandlerProvider(handler), uriTemplate, uriVariables); + } + public WebSocketSession doHandshake(HandlerProvider handler, String uriTemplate, Object... uriVariables) throws WebSocketConnectFailureException { diff --git a/spring-websocket/src/main/java/org/springframework/websocket/endpoint/WebSocketHandlerEndpoint.java b/spring-websocket/src/main/java/org/springframework/websocket/endpoint/WebSocketHandlerEndpoint.java index 7f7bd50a45..1b15116486 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/endpoint/WebSocketHandlerEndpoint.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/endpoint/WebSocketHandlerEndpoint.java @@ -67,7 +67,7 @@ public class WebSocketHandlerEndpoint extends Endpoint { Assert.isTrue(this.sessionCount.compareAndSet(0, 1), "Unexpected connection"); if (logger.isDebugEnabled()) { - logger.debug("Client connected, javax.websocket.Session id=" + logger.debug("Connection established, javax.websocket.Session id=" + session.getId() + ", uri=" + session.getRequestURI()); } @@ -110,7 +110,7 @@ public class WebSocketHandlerEndpoint extends Endpoint { this.handler.afterConnectionEstablished(this.webSocketSession); } catch (Throwable ex) { - this.handler.handleError(ex, this.webSocketSession); + onError(session, ex); } } @@ -123,7 +123,7 @@ public class WebSocketHandlerEndpoint extends Endpoint { ((TextMessageHandler) handler).handleTextMessage(textMessage, this.webSocketSession); } catch (Throwable ex) { - this.handler.handleError(ex, this.webSocketSession); + onError(session, ex); } } @@ -136,21 +136,21 @@ public class WebSocketHandlerEndpoint extends Endpoint { ((BinaryMessageHandler) handler).handleBinaryMessage(binaryMessage, this.webSocketSession); } catch (Throwable ex) { - this.handler.handleError(ex, this.webSocketSession); + onError(session, ex); } } @Override public void onClose(javax.websocket.Session session, CloseReason reason) { if (logger.isDebugEnabled()) { - logger.debug("Client disconnected, WebSocket session id=" + session.getId() + ", " + reason); + logger.debug("Connection closed, WebSocket session id=" + session.getId() + ", " + reason); } try { CloseStatus closeStatus = new CloseStatus(reason.getCloseCode().getCode(), reason.getReasonPhrase()); this.handler.afterConnectionClosed(closeStatus, this.webSocketSession); } catch (Throwable ex) { - logger.error("Error while processing session closing", ex); + onError(session, ex); } finally { this.handlerProvider.destroy(this.handler); diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/support/JettyRequestUpgradeStrategy.java b/spring-websocket/src/main/java/org/springframework/websocket/server/support/JettyRequestUpgradeStrategy.java index a00ee912ef..6be0568cb8 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/server/support/JettyRequestUpgradeStrategy.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/support/JettyRequestUpgradeStrategy.java @@ -143,7 +143,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy { try { this.session = new WebSocketSessionAdapter(session); if (logger.isDebugEnabled()) { - logger.debug("Client connected, WebSocket session id=" + logger.debug("Connection established, WebSocket session id=" + this.session.getId() + ", uri=" + this.session.getURI()); } this.handler = this.provider.getHandler(); @@ -167,7 +167,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy { try { CloseStatus closeStatus = new CloseStatus(statusCode, reason); if (logger.isDebugEnabled()) { - logger.debug("Client disconnected, WebSocket session id=" + logger.debug("Connection closed, WebSocket session id=" + this.session.getId() + ", " + closeStatus); } this.handler.afterConnectionClosed(closeStatus, this.session); diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/support/WebSocketHttpRequestHandler.java b/spring-websocket/src/main/java/org/springframework/websocket/server/support/WebSocketHttpRequestHandler.java index 096ee1ca0b..343b065f55 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/server/support/WebSocketHttpRequestHandler.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/support/WebSocketHttpRequestHandler.java @@ -44,25 +44,26 @@ import org.springframework.websocket.support.SimpleHandlerProvider; */ public class WebSocketHttpRequestHandler implements HttpRequestHandler { - private HandshakeHandler handshakeHandler; + private final HandshakeHandler handshakeHandler; private final HandlerProvider handlerProvider; public WebSocketHttpRequestHandler(WebSocketHandler webSocketHandler) { - Assert.notNull(webSocketHandler, "webSocketHandler is required"); - this.handlerProvider = new SimpleHandlerProvider(webSocketHandler); - this.handshakeHandler = new DefaultHandshakeHandler(); + this(new SimpleHandlerProvider(webSocketHandler)); } public WebSocketHttpRequestHandler( HandlerProvider handlerProvider) { - Assert.notNull(handlerProvider, "handlerProvider is required"); - this.handlerProvider = handlerProvider; + this(handlerProvider, new DefaultHandshakeHandler()); } - public void setHandshakeHandler(HandshakeHandler handshakeHandler) { + public WebSocketHttpRequestHandler( HandlerProvider handlerProvider, + HandshakeHandler handshakeHandler) { + + Assert.notNull(handlerProvider, "handlerProvider is required"); Assert.notNull(handshakeHandler, "handshakeHandler is required"); - this.handshakeHandler = handshakeHandler; + this.handlerProvider = handlerProvider; + this.handshakeHandler = new DefaultHandshakeHandler(); } @Override