diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsConfiguration.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsConfiguration.java deleted file mode 100644 index f7cc5fd797..0000000000 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsConfiguration.java +++ /dev/null @@ -1,63 +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.web.socket.sockjs; - -import org.springframework.scheduling.TaskScheduler; - -/** - * SockJS configuration options that need to be made available to {@link TransportHandler} - * s and SockJS sessions. - * - * @author Rossen Stoyanchev - * @since 4.0 - */ -public interface SockJsConfiguration { - - /** - * Streaming transports save responses on the client side and don't free - * memory used by delivered messages. Such transports need to recycle the - * connection once in a while. This property sets a minimum number of bytes - * that can be send over a single HTTP streaming request before it will be - * 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. - * - *

The default value is 128K (i.e. 128 * 1024). - */ - int getStreamBytesLimit(); - - /** - * 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. - * - *

The default value is 25,000 (25 seconds). - */ - long getHeartbeatTime(); - - /** - * A scheduler instance to use for scheduling heart-beat messages. - */ - TaskScheduler getTaskScheduler(); - - /** - * The codec to use for encoding and decoding SockJS messages. - * @exception IllegalStateException if no {@link SockJsMessageCodec} is available - */ - SockJsMessageCodec getMessageCodecRequired(); - -} diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/SockJsHttpRequestHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsHttpRequestHandler.java similarity index 79% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/SockJsHttpRequestHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsHttpRequestHandler.java index 3ae8cf7c17..2d152c9055 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/SockJsHttpRequestHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsHttpRequestHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.support; +package org.springframework.web.socket.sockjs; import java.io.IOException; @@ -29,20 +29,12 @@ import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.util.Assert; import org.springframework.web.HttpRequestHandler; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.SockJsService; import org.springframework.web.socket.support.ExceptionWebSocketHandlerDecorator; import org.springframework.web.socket.support.LoggingWebSocketHandlerDecorator; /** - * 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. - * - *

The {@link #decorateWebSocketHandler(WebSocketHandler)} method decorates the given - * WebSocketHandler with a logging and exception handling decorators. This method can be - * overridden to change that. + * An {@link HttpRequestHandler} that allows mapping a {@link SockJsService} to requests + * in a Servlet container. * * @author Rossen Stoyanchev * @since 4.0 diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/TransportErrorException.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsProcessingException.java similarity index 52% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/TransportErrorException.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsProcessingException.java index 912712600a..78d4ac26ee 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/TransportErrorException.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsProcessingException.java @@ -17,37 +17,31 @@ 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. If the underlying - * exception occurs while sending messages to the client, the session is closed and the - * {@link WebSocketHandler} notified. - * - *

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 SockJS request handling fails. * * @author Rossen Stoyanchev * @since 4.0 */ @SuppressWarnings("serial") -public class TransportErrorException extends NestedRuntimeException { +public class SockJsProcessingException extends NestedRuntimeException { - private final String sockJsSessionId; + private final String sessionId; - public TransportErrorException(String msg, Throwable cause, String sockJsSessionId) { + + public SockJsProcessingException(String msg, Throwable cause, String sessionId) { super(msg, cause); - this.sockJsSessionId = sockJsSessionId; + this.sessionId = sessionId; } public String getSockJsSessionId() { - return this.sockJsSessionId; + return this.sessionId; } @Override public String getMessage() { - return "Transport error for SockJS session id=" + this.sockJsSessionId + ", " + super.getMessage(); + return "Transport error for SockJS session id=" + this.sessionId + ", " + super.getMessage(); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsService.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsService.java index ad282ce231..365c6d13eb 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsService.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsService.java @@ -23,16 +23,17 @@ import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; /** - * A service for processing SockJS requests. + * A service for processing SockJS HTTP requests. * * @author Rossen Stoyanchev * @since 4.0 * - * @see org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler + * @see SockJsHttpRequestHandler */ public interface SockJsService { + void handleRequest(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler) - throws IOException, TransportErrorException; + throws IOException, SockJsProcessingException; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/package-info.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/package-info.java index d523c864b3..0b29a72937 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/package-info.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/package-info.java @@ -15,7 +15,7 @@ */ /** - * Common abstractions for the SockJS protocol. + * Top-level SockJS types. */ package org.springframework.web.socket.sockjs; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/AbstractSockJsService.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/AbstractSockJsService.java similarity index 89% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/AbstractSockJsService.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/AbstractSockJsService.java index 49593d538c..f80c92ddbf 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/AbstractSockJsService.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/AbstractSockJsService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs; +package org.springframework.web.socket.sockjs.support; import java.io.IOException; import java.nio.charset.Charset; @@ -44,6 +44,8 @@ import org.springframework.util.DigestUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.sockjs.SockJsProcessingException; +import org.springframework.web.socket.sockjs.SockJsService; /** * An abstract base class for {@link SockJsService} implementations that provides SockJS @@ -63,7 +65,7 @@ import org.springframework.web.socket.WebSocketHandler; * @author Rossen Stoyanchev * @since 4.0 */ -public abstract class AbstractSockJsService implements SockJsService, SockJsConfiguration { +public abstract class AbstractSockJsService implements SockJsService { protected final Log logger = LogFactory.getLog(getClass()); @@ -153,9 +155,8 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf *

By default this is set to point to * "https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js". */ - public AbstractSockJsService setSockJsClientLibraryUrl(String clientLibraryUrl) { + public void setSockJsClientLibraryUrl(String clientLibraryUrl) { this.clientLibraryUrl = clientLibraryUrl; - return this; } /** @@ -166,12 +167,21 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf return this.clientLibraryUrl; } - public AbstractSockJsService setStreamBytesLimit(int streamBytesLimit) { + /** + * Streaming transports save responses on the client side and don't free + * memory used by delivered messages. Such transports need to recycle the + * connection once in a while. This property sets a minimum number of bytes + * that can be send over a single HTTP streaming request before it will be + * 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. + * + *

The default value is 128K (i.e. 128 * 1024). + */ + public void setStreamBytesLimit(int streamBytesLimit) { this.streamBytesLimit = streamBytesLimit; - return this; } - @Override public int getStreamBytesLimit() { return this.streamBytesLimit; } @@ -184,9 +194,8 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf *

Set this option to indicate if a JSESSIONID cookie should be created. The * default value is "true". */ - public AbstractSockJsService setJsessionIdCookieRequired(boolean jsessionIdCookieRequired) { + public void setJsessionIdCookieRequired(boolean jsessionIdCookieRequired) { this.jsessionIdCookieRequired = jsessionIdCookieRequired; - return this; } /** @@ -197,17 +206,24 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf return this.jsessionIdCookieRequired; } - public AbstractSockJsService setHeartbeatTime(long heartbeatTime) { + /** + * 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. + * + *

The default value is 25,000 (25 seconds). + */ + public void setHeartbeatTime(long heartbeatTime) { this.heartbeatTime = heartbeatTime; - return this; } - @Override public long getHeartbeatTime() { return this.heartbeatTime; } - @Override + /** + * A scheduler instance to use for scheduling heart-beat messages. + */ public TaskScheduler getTaskScheduler() { return this.taskScheduler; } @@ -253,7 +269,7 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf */ @Override public final void handleRequest(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler) - throws IOException, TransportErrorException { + throws IOException, SockJsProcessingException { String sockJsPath = getSockJsPath(request); if (sockJsPath == null) { @@ -307,7 +323,7 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf return; } - handleTransportRequest(request, response, sessionId, TransportType.fromValue(transport), handler); + handleTransportRequest(request, response, handler, sessionId, transport); } finally { response.flush(); @@ -321,7 +337,7 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf String path = request.getURI().getPath(); - // SockJS prefix hints? + // Try SockJS prefix hints if (!this.validSockJsPrefixes.isEmpty()) { for (String prefix : this.validSockJsPrefixes) { int index = path.indexOf(prefix); @@ -333,7 +349,7 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf return null; } - // SockJS info request? + // Try SockJS info request if (path.endsWith("/info")) { this.knownSockJsPrefixes.add(path.substring(0, path.length() - "/info".length())); return "/info"; @@ -357,11 +373,11 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf return result; } - // SockJS greeting? + // Try SockJS greeting String pathNoSlash = path.endsWith("/") ? path.substring(0, path.length() - 1) : path; String lastSegment = pathNoSlash.substring(pathNoSlash.lastIndexOf('/') + 1); - if ((TransportType.fromValue(lastSegment) == null) && !lastSegment.startsWith("iframe")) { + if (!isValidTransportType(lastSegment) && !lastSegment.startsWith("iframe")) { this.knownSockJsPrefixes.add(path); return ""; } @@ -369,12 +385,14 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf return null; } + protected abstract boolean isValidTransportType(String transportType); + protected abstract void handleRawWebSocketRequest(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler webSocketHandler) throws IOException; protected abstract void handleTransportRequest(ServerHttpRequest request, ServerHttpResponse response, - String sessionId, TransportType transportType, WebSocketHandler webSocketHandler) - throws IOException, TransportErrorException; + WebSocketHandler webSocketHandler, String sessionId, String transport) + throws IOException, SockJsProcessingException; protected boolean validateRequest(String serverId, String sessionId, String transport) { @@ -390,7 +408,7 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf return false; } - if (!isWebSocketEnabled() && transport.equals(TransportType.WEBSOCKET.value())) { + if (!isWebSocketEnabled() && transport.equals("websocket")) { logger.warn("Websocket transport is disabled"); return false; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/AbstractSockJsMessageCodec.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/AbstractSockJsMessageCodec.java similarity index 95% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/AbstractSockJsMessageCodec.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/AbstractSockJsMessageCodec.java index 893113a058..c3b3a7087d 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/AbstractSockJsMessageCodec.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/AbstractSockJsMessageCodec.java @@ -14,10 +14,9 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.support; +package org.springframework.web.socket.sockjs.support.frame; import org.springframework.util.Assert; -import org.springframework.web.socket.sockjs.SockJsMessageCodec; /** diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/Jackson2SockJsMessageCodec.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/Jackson2SockJsMessageCodec.java similarity index 96% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/Jackson2SockJsMessageCodec.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/Jackson2SockJsMessageCodec.java index b9b5617cd3..04699413d1 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/Jackson2SockJsMessageCodec.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/Jackson2SockJsMessageCodec.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.support; +package org.springframework.web.socket.sockjs.support.frame; import java.io.IOException; import java.io.InputStream; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/JacksonSockJsMessageCodec.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/JacksonSockJsMessageCodec.java similarity index 96% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/JacksonSockJsMessageCodec.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/JacksonSockJsMessageCodec.java index 34f37c5f2f..6f5ed64490 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/JacksonSockJsMessageCodec.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/JacksonSockJsMessageCodec.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.support; +package org.springframework.web.socket.sockjs.support.frame; import java.io.IOException; import java.io.InputStream; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsFrame.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/SockJsFrame.java similarity index 98% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsFrame.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/SockJsFrame.java index 4c1a374ea7..66389c6353 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsFrame.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/SockJsFrame.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs; +package org.springframework.web.socket.sockjs.support.frame; import java.nio.charset.Charset; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsMessageCodec.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/SockJsMessageCodec.java similarity index 96% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsMessageCodec.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/SockJsMessageCodec.java index a4fabe891a..c20324679f 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsMessageCodec.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/SockJsMessageCodec.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs; +package org.springframework.web.socket.sockjs.support.frame; import java.io.IOException; import java.io.InputStream; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/package-info.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/package-info.java new file mode 100644 index 0000000000..d29096e92e --- /dev/null +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/frame/package-info.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * Support classes for creating SockJS frames including the encoding and decoding + * of SockJS message frames. + */ +package org.springframework.web.socket.sockjs.support.frame; + diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/package-info.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/package-info.java index 2359960d30..452287e364 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/package-info.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/package-info.java @@ -15,7 +15,9 @@ */ /** - * Support classes for the SockJS implementation. + * Support classes for SockJS including an + * {@link org.springframework.web.socket.sockjs.support.AbstractSockJsService} + * implementation. */ package org.springframework.web.socket.sockjs.support; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/TransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandler.java similarity index 59% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/TransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandler.java index 70449d59ff..4a6ed8e295 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/TransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandler.java @@ -14,31 +14,25 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs; +package org.springframework.web.socket.sockjs.transport; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.sockjs.SockJsProcessingException; /** - * A contract for SockJS transport implementations. A {@link TransportHandler} is closely - * related to and often delegates to an {@link AbstractSockJsSession}. In fact most - * transports are also implementations of {@link SockJsSessionFactory} with the only exception - * to that being HTTP transports that receive messages as they depend on finding an existing - * session. See {@link TransportType} for a list of all available transport types. + * Handles SockJS session URLs. * * @author Rossen Stoyanchev * @since 4.0 - * - * @see SockJsService */ public interface TransportHandler { TransportType getTransportType(); - void setSockJsConfiguration(SockJsConfiguration sockJsConfig); - void handleRequest(ServerHttpRequest request, ServerHttpResponse response, - WebSocketHandler handler, AbstractSockJsSession session) throws TransportErrorException; + WebSocketHandler handler, WebSocketSession session) throws SockJsProcessingException; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/TransportType.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportType.java similarity index 96% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/TransportType.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportType.java index a9b53a84c9..f9a93d5c1e 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/TransportType.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportType.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs; +package org.springframework.web.socket.sockjs.transport; import java.util.Arrays; import java.util.Collections; @@ -25,7 +25,7 @@ import java.util.Map; import org.springframework.http.HttpMethod; /** - * SockJS server transport types. + * Defines SockJS transport types. * * @author Rossen Stoyanchev * @since 4.0 diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/AbstractHttpReceivingTransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/AbstractHttpReceivingTransportHandler.java similarity index 68% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/AbstractHttpReceivingTransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/AbstractHttpReceivingTransportHandler.java index 8320969e15..690b87d043 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/AbstractHttpReceivingTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/AbstractHttpReceivingTransportHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.io.IOException; import java.nio.charset.Charset; @@ -24,10 +24,11 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; +import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.AbstractSockJsSession; -import org.springframework.web.socket.sockjs.TransportErrorException; -import org.springframework.web.socket.sockjs.TransportHandler; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.sockjs.SockJsProcessingException; +import org.springframework.web.socket.sockjs.transport.TransportHandler; import org.springframework.web.socket.support.ExceptionWebSocketHandlerDecorator; import com.fasterxml.jackson.databind.JsonMappingException; @@ -44,22 +45,16 @@ public abstract class AbstractHttpReceivingTransportHandler @Override public final void handleRequest(ServerHttpRequest request, ServerHttpResponse response, - WebSocketHandler webSocketHandler, AbstractSockJsSession session) throws TransportErrorException { - - if (session == null) { - response.setStatusCode(HttpStatus.NOT_FOUND); - logger.warn("Session not found"); - return; - } + WebSocketHandler webSocketHandler, WebSocketSession webSocketSession) throws SockJsProcessingException { // TODO: check "Sec-WebSocket-Protocol" header // https://github.com/sockjs/sockjs-client/issues/130 - handleRequestInternal(request, response, session); + handleRequestInternal(request, response, webSocketHandler, webSocketSession); } protected void handleRequestInternal(ServerHttpRequest request, ServerHttpResponse response, - AbstractSockJsSession session) throws TransportErrorException { + WebSocketHandler wsHandler, WebSocketSession wsSession) throws SockJsProcessingException { String[] messages = null; try { @@ -67,22 +62,22 @@ public abstract class AbstractHttpReceivingTransportHandler } catch (JsonMappingException ex) { logger.error("Failed to read message: " + ex.getMessage()); - sendInternalServerError(response, "Payload expected.", session.getId()); + sendInternalServerError(response, "Payload expected.", wsSession.getId()); return; } catch (IOException ex) { logger.error("Failed to read message: " + ex.getMessage()); - sendInternalServerError(response, "Broken JSON encoding.", session.getId()); + sendInternalServerError(response, "Broken JSON encoding.", wsSession.getId()); return; } catch (Throwable t) { logger.error("Failed to read message: " + t.getMessage()); - sendInternalServerError(response, "Failed to process messages", session.getId()); + sendInternalServerError(response, "Failed to process messages", wsSession.getId()); return; } if (messages == null) { - sendInternalServerError(response, "Payload expected.", session.getId()); + sendInternalServerError(response, "Payload expected.", wsSession.getId()); return; } @@ -94,23 +89,25 @@ public abstract class AbstractHttpReceivingTransportHandler response.getHeaders().setContentType(new MediaType("text", "plain", Charset.forName("UTF-8"))); try { - session.delegateMessages(messages); + for (String message : messages) { + wsHandler.handleMessage(wsSession, new TextMessage(message)); + } } catch (Throwable t) { - ExceptionWebSocketHandlerDecorator.tryCloseWithError(session, t, logger); - throw new TransportErrorException("Unhandled WebSocketHandler error in " + this, t, session.getId()); + ExceptionWebSocketHandlerDecorator.tryCloseWithError(wsSession, t, logger); + throw new SockJsProcessingException("Unhandled WebSocketHandler error in " + this, t, wsSession.getId()); } } protected void sendInternalServerError(ServerHttpResponse response, String error, - String sessionId) throws TransportErrorException { + String sessionId) throws SockJsProcessingException { try { response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); response.getBody().write(error.getBytes("UTF-8")); } catch (Throwable t) { - throw new TransportErrorException("Failed to send error message to client", t, sessionId); + throw new SockJsProcessingException("Failed to send error message to client", t, sessionId); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/AbstractHttpSendingTransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/AbstractHttpSendingTransportHandler.java similarity index 63% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/AbstractHttpSendingTransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/AbstractHttpSendingTransportHandler.java index 8d58423714..ccdb07bbff 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/AbstractHttpSendingTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/AbstractHttpSendingTransportHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.io.IOException; @@ -22,12 +22,12 @@ import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.SockJsFrame; -import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat; -import org.springframework.web.socket.sockjs.AbstractSockJsSession; -import org.springframework.web.socket.sockjs.SockJsSessionFactory; -import org.springframework.web.socket.sockjs.TransportErrorException; -import org.springframework.web.socket.sockjs.TransportHandler; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.sockjs.SockJsProcessingException; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat; +import org.springframework.web.socket.sockjs.transport.TransportHandler; +import org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession; /** * Base class for HTTP-based transports that send messages over HTTP. @@ -41,34 +41,34 @@ public abstract class AbstractHttpSendingTransportHandler extends TransportHandl @Override public final void handleRequest(ServerHttpRequest request, ServerHttpResponse response, - WebSocketHandler webSocketHandler, AbstractSockJsSession session) throws TransportErrorException { + WebSocketHandler webSocketHandler, WebSocketSession session) throws SockJsProcessingException { // Set content type before writing response.getHeaders().setContentType(getContentType()); - AbstractHttpSockJsSession httpServerSession = (AbstractHttpSockJsSession) session; - handleRequestInternal(request, response, httpServerSession); + AbstractHttpSockJsSession sockJsSession = (AbstractHttpSockJsSession) session; + handleRequestInternal(request, response, sockJsSession); } protected void handleRequestInternal(ServerHttpRequest request, ServerHttpResponse response, - AbstractHttpSockJsSession httpServerSession) throws TransportErrorException { + AbstractHttpSockJsSession sockJsSession) throws SockJsProcessingException { - if (httpServerSession.isNew()) { + if (sockJsSession.isNew()) { logger.debug("Opening " + getTransportType() + " connection"); - httpServerSession.setInitialRequest(request, response, getFrameFormat(request)); + sockJsSession.setInitialRequest(request, response, getFrameFormat(request)); } - else if (!httpServerSession.isActive()) { + else if (!sockJsSession.isActive()) { logger.debug("starting " + getTransportType() + " async request"); - httpServerSession.setLongPollingRequest(request, response, getFrameFormat(request)); + sockJsSession.setLongPollingRequest(request, response, getFrameFormat(request)); } else { try { - logger.debug("another " + getTransportType() + " connection still open: " + httpServerSession); + logger.debug("another " + getTransportType() + " connection still open: " + sockJsSession); SockJsFrame closeFrame = SockJsFrame.closeFrameAnotherConnectionOpen(); response.getBody().write(getFrameFormat(request).format(closeFrame).getContentBytes()); } catch (IOException e) { - throw new TransportErrorException("Failed to send SockJS close frame", e, httpServerSession.getId()); + throw new SockJsProcessingException("Failed to send SockJS close frame", e, sockJsSession.getId()); } } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/DefaultSockJsService.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/DefaultSockJsService.java similarity index 68% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/DefaultSockJsService.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/DefaultSockJsService.java index 2be0f0f790..2248664a90 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/DefaultSockJsService.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/DefaultSockJsService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.io.IOException; import java.util.Arrays; @@ -39,18 +39,19 @@ import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.server.DefaultHandshakeHandler; import org.springframework.web.socket.server.HandshakeHandler; import org.springframework.web.socket.server.support.ServerWebSocketSessionInitializer; -import org.springframework.web.socket.sockjs.AbstractSockJsService; -import org.springframework.web.socket.sockjs.AbstractSockJsSession; -import org.springframework.web.socket.sockjs.SockJsMessageCodec; +import org.springframework.web.socket.sockjs.SockJsProcessingException; import org.springframework.web.socket.sockjs.SockJsService; -import org.springframework.web.socket.sockjs.SockJsSessionFactory; -import org.springframework.web.socket.sockjs.TransportErrorException; -import org.springframework.web.socket.sockjs.TransportHandler; -import org.springframework.web.socket.sockjs.TransportType; -import org.springframework.web.socket.sockjs.support.Jackson2SockJsMessageCodec; +import org.springframework.web.socket.sockjs.support.AbstractSockJsService; +import org.springframework.web.socket.sockjs.support.frame.Jackson2SockJsMessageCodec; +import org.springframework.web.socket.sockjs.support.frame.SockJsMessageCodec; +import org.springframework.web.socket.sockjs.transport.TransportHandler; +import org.springframework.web.socket.sockjs.transport.TransportType; +import org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession; +import org.springframework.web.socket.sockjs.transport.session.SockJsServiceConfig; /** @@ -159,12 +160,18 @@ public class DefaultSockJsService extends AbstractSockJsService { protected void addTransportHandlers(Collection handlers) { for (TransportHandler handler : handlers) { - handler.setSockJsConfiguration(this); + if (handler instanceof TransportHandlerSupport) { + ((TransportHandlerSupport) handler).setSockJsServiceConfiguration(this.sockJsServiceConfig); + } this.transportHandlers.put(handler.getTransportType(), handler); } } + /** + * The codec to use for encoding and decoding SockJS messages. + * @exception IllegalStateException if no {@link SockJsMessageCodec} is available + */ public void setMessageCodec(SockJsMessageCodec messageCodec) { this.messageCodec = messageCodec; } @@ -173,13 +180,6 @@ public class DefaultSockJsService extends AbstractSockJsService { return this.messageCodec; } - @Override - public SockJsMessageCodec getMessageCodecRequired() { - Assert.state(this.messageCodec != null, "A SockJsMessageCodec is required but not available." - + " Either add Jackson 2 or Jackson 1.x to the classpath, or configure a SockJsMessageCode"); - return this.messageCodec; - } - public Map getTransportHandlers() { return Collections.unmodifiableMap(this.transportHandlers); } @@ -203,11 +203,17 @@ public class DefaultSockJsService extends AbstractSockJsService { @Override protected void handleTransportRequest(ServerHttpRequest request, ServerHttpResponse response, - String sessionId, TransportType transportType, WebSocketHandler webSocketHandler) - throws IOException, TransportErrorException { + WebSocketHandler wsHandler, String sessionId, String transport) + throws IOException, SockJsProcessingException { + + TransportType transportType = TransportType.fromValue(transport); + if (transportType == null) { + logger.debug("Unknown transport type: " + transportType); + response.setStatusCode(HttpStatus.NOT_FOUND); + return; + } TransportHandler transportHandler = this.transportHandlers.get(transportType); - if (transportHandler == null) { logger.debug("Transport handler not found"); response.setStatusCode(HttpStatus.NOT_FOUND); @@ -231,58 +237,60 @@ public class DefaultSockJsService extends AbstractSockJsService { return; } - AbstractSockJsSession session = getSockJsSession(sessionId, webSocketHandler, - transportHandler, request, response); - - if (session != null) { - if (transportType.sendsNoCacheInstruction()) { - addNoCacheHeaders(response); - } - - if (transportType.setsJsessionId() && isJsessionIdCookieRequired()) { - Cookie cookie = request.getCookies().getCookie("JSESSIONID"); - String jsid = (cookie != null) ? cookie.getValue() : "dummy"; - // TODO: bypass use of Cookie object (causes Jetty to set Expires header) - response.getHeaders().set("Set-Cookie", "JSESSIONID=" + jsid + ";path=/"); - } - - if (transportType.supportsCors()) { - addCorsHeaders(request, response); + WebSocketSession session = this.sessions.get(sessionId); + if (session == null) { + if (transportHandler instanceof SockJsSessionFactory) { + SockJsSessionFactory sessionFactory = (SockJsSessionFactory) transportHandler; + session = createSockJsSession(sessionId, sessionFactory, wsHandler, request, response); } } + if (session == null) { + response.setStatusCode(HttpStatus.NOT_FOUND); + logger.warn("Session not found"); + return; + } - transportHandler.handleRequest(request, response, webSocketHandler, session); + if (transportType.sendsNoCacheInstruction()) { + addNoCacheHeaders(response); + } + + if (transportType.setsJsessionId() && isJsessionIdCookieRequired()) { + Cookie cookie = request.getCookies().getCookie("JSESSIONID"); + String jsid = (cookie != null) ? cookie.getValue() : "dummy"; + // TODO: bypass use of Cookie object (causes Jetty to set Expires header) + response.getHeaders().set("Set-Cookie", "JSESSIONID=" + jsid + ";path=/"); + } + + if (transportType.supportsCors()) { + addCorsHeaders(request, response); + } + + transportHandler.handleRequest(request, response, wsHandler, session); } - protected AbstractSockJsSession getSockJsSession(String sessionId, WebSocketHandler handler, - TransportHandler transportHandler, ServerHttpRequest request, ServerHttpResponse response) { + private WebSocketSession createSockJsSession(String sessionId, SockJsSessionFactory sessionFactory, + WebSocketHandler handler, ServerHttpRequest request, ServerHttpResponse response) { - AbstractSockJsSession session = this.sessions.get(sessionId); - if (session != null) { - return session; - } - - if (transportHandler instanceof SockJsSessionFactory) { - SockJsSessionFactory sessionFactory = (SockJsSessionFactory) transportHandler; - - synchronized (this.sessions) { - session = this.sessions.get(sessionId); - if (session != null) { - return session; - } - if (this.sessionCleanupTask == null) { - scheduleSessionTask(); - } - logger.debug("Creating new session with session id \"" + sessionId + "\""); - session = sessionFactory.createSession(sessionId, handler); - String protocol = null; // TODO: https://github.com/sockjs/sockjs-client/issues/130 - this.sessionInitializer.initialize(request, response, protocol, session); - this.sessions.put(sessionId, session); + synchronized (this.sessions) { + AbstractSockJsSession session = this.sessions.get(sessionId); + if (session != null) { return session; } + if (this.sessionCleanupTask == null) { + scheduleSessionTask(); + } + logger.debug("Creating new session with session id \"" + sessionId + "\""); + session = sessionFactory.createSession(sessionId, handler); + String protocol = null; // TODO: https://github.com/sockjs/sockjs-client/issues/130 + this.sessionInitializer.initialize(request, response, protocol, session); + this.sessions.put(sessionId, session); + return session; } + } - return null; + @Override + protected boolean isValidTransportType(String lastSegment) { + return TransportType.fromValue(lastSegment) != null; } private void scheduleSessionTask() { @@ -314,4 +322,31 @@ public class DefaultSockJsService extends AbstractSockJsService { }, getDisconnectDelay()); } + + private final SockJsServiceConfig sockJsServiceConfig = new SockJsServiceConfig() { + + @Override + public int getStreamBytesLimit() { + return DefaultSockJsService.this.getStreamBytesLimit(); + } + + @Override + public long getHeartbeatTime() { + return DefaultSockJsService.this.getHeartbeatTime(); + } + + @Override + public TaskScheduler getTaskScheduler() { + return DefaultSockJsService.this.getTaskScheduler(); + } + + @Override + public SockJsMessageCodec getMessageCodec() { + Assert.state(DefaultSockJsService.this.getMessageCodec() != null, + "A SockJsMessageCodec is required but not available." + + " Either add Jackson 2 or Jackson 1.x to the classpath, or configure a SockJsMessageCode"); + return DefaultSockJsService.this.getMessageCodec(); + } + }; + } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/EventSourceTransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/EventSourceTransportHandler.java similarity index 78% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/EventSourceTransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/EventSourceTransportHandler.java index ea986bf55d..082a8e181a 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/EventSourceTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/EventSourceTransportHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.io.IOException; import java.nio.charset.Charset; @@ -22,10 +22,11 @@ import java.nio.charset.Charset; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.SockJsConfiguration; -import org.springframework.web.socket.sockjs.SockJsFrame.DefaultFrameFormat; -import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat; -import org.springframework.web.socket.sockjs.TransportType; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.DefaultFrameFormat; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat; +import org.springframework.web.socket.sockjs.transport.TransportType; +import org.springframework.web.socket.sockjs.transport.session.SockJsServiceConfig; +import org.springframework.web.socket.sockjs.transport.session.StreamingSockJsSession; /** * A TransportHandler for sending messages via Server-Sent events: @@ -49,7 +50,7 @@ public class EventSourceTransportHandler extends AbstractHttpSendingTransportHan @Override public StreamingSockJsSession createSession(String sessionId, WebSocketHandler handler) { - return new EventSourceStreamingSockJsSession(sessionId, getSockJsConfig(), handler); + return new EventSourceStreamingSockJsSession(sessionId, getSockJsServiceConfig(), handler); } @Override @@ -60,7 +61,7 @@ public class EventSourceTransportHandler extends AbstractHttpSendingTransportHan private final class EventSourceStreamingSockJsSession extends StreamingSockJsSession { - private EventSourceStreamingSockJsSession(String sessionId, SockJsConfiguration config, WebSocketHandler handler) { + private EventSourceStreamingSockJsSession(String sessionId, SockJsServiceConfig config, WebSocketHandler handler) { super(sessionId, config, handler); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/HtmlFileTransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/HtmlFileTransportHandler.java similarity index 81% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/HtmlFileTransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/HtmlFileTransportHandler.java index ed76baf698..72606b2081 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/HtmlFileTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/HtmlFileTransportHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.io.IOException; import java.nio.charset.Charset; @@ -25,12 +25,14 @@ import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.util.StringUtils; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.SockJsConfiguration; -import org.springframework.web.socket.sockjs.SockJsFrame.DefaultFrameFormat; -import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat; -import org.springframework.web.socket.sockjs.TransportErrorException; -import org.springframework.web.socket.sockjs.TransportHandler; -import org.springframework.web.socket.sockjs.TransportType; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.DefaultFrameFormat; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat; +import org.springframework.web.socket.sockjs.transport.TransportHandler; +import org.springframework.web.socket.sockjs.transport.TransportType; +import org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession; +import org.springframework.web.socket.sockjs.transport.session.SockJsServiceConfig; +import org.springframework.web.socket.sockjs.transport.session.StreamingSockJsSession; +import org.springframework.web.socket.sockjs.SockJsProcessingException; import org.springframework.web.util.JavaScriptUtils; /** @@ -85,12 +87,12 @@ public class HtmlFileTransportHandler extends AbstractHttpSendingTransportHandle @Override public StreamingSockJsSession createSession(String sessionId, WebSocketHandler handler) { - return new HtmlFileStreamingSockJsSession(sessionId, getSockJsConfig(), handler); + return new HtmlFileStreamingSockJsSession(sessionId, getSockJsServiceConfig(), handler); } @Override public void handleRequestInternal(ServerHttpRequest request, ServerHttpResponse response, - AbstractHttpSockJsSession session) throws TransportErrorException { + AbstractHttpSockJsSession session) throws SockJsProcessingException { try { String callback = request.getQueryParams().getFirst("c"); @@ -101,7 +103,7 @@ public class HtmlFileTransportHandler extends AbstractHttpSendingTransportHandle } } catch (Throwable t) { - throw new TransportErrorException("Failed to send error to client", t, session.getId()); + throw new SockJsProcessingException("Failed to send error to client", t, session.getId()); } super.handleRequestInternal(request, response, session); } @@ -119,7 +121,7 @@ public class HtmlFileTransportHandler extends AbstractHttpSendingTransportHandle private final class HtmlFileStreamingSockJsSession extends StreamingSockJsSession { - private HtmlFileStreamingSockJsSession(String sessionId, SockJsConfiguration config, WebSocketHandler handler) { + private HtmlFileStreamingSockJsSession(String sessionId, SockJsServiceConfig config, WebSocketHandler handler) { super(sessionId, config, handler); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/JsonpPollingTransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/JsonpPollingTransportHandler.java similarity index 75% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/JsonpPollingTransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/JsonpPollingTransportHandler.java index 0b134f442c..ea8e81bd85 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/JsonpPollingTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/JsonpPollingTransportHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.nio.charset.Charset; @@ -24,10 +24,12 @@ import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.util.StringUtils; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.SockJsFrame; -import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat; -import org.springframework.web.socket.sockjs.TransportErrorException; -import org.springframework.web.socket.sockjs.TransportType; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat; +import org.springframework.web.socket.sockjs.transport.TransportType; +import org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession; +import org.springframework.web.socket.sockjs.transport.session.PollingSockJsSession; +import org.springframework.web.socket.sockjs.SockJsProcessingException; import org.springframework.web.util.JavaScriptUtils; /** @@ -50,12 +52,12 @@ public class JsonpPollingTransportHandler extends AbstractHttpSendingTransportHa @Override public PollingSockJsSession createSession(String sessionId, WebSocketHandler handler) { - return new PollingSockJsSession(sessionId, getSockJsConfig(), handler); + return new PollingSockJsSession(sessionId, getSockJsServiceConfig(), handler); } @Override public void handleRequestInternal(ServerHttpRequest request, ServerHttpResponse response, - AbstractHttpSockJsSession session) throws TransportErrorException { + AbstractHttpSockJsSession session) throws SockJsProcessingException { try { String callback = request.getQueryParams().getFirst("c"); @@ -66,7 +68,7 @@ public class JsonpPollingTransportHandler extends AbstractHttpSendingTransportHa } } catch (Throwable t) { - throw new TransportErrorException("Failed to send error to client", t, session.getId()); + throw new SockJsProcessingException("Failed to send error to client", t, session.getId()); } super.handleRequestInternal(request, response, session); diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/JsonpTransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/JsonpTransportHandler.java similarity index 72% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/JsonpTransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/JsonpTransportHandler.java index 98777f3c6e..eafc0f84eb 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/JsonpTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/JsonpTransportHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.io.IOException; @@ -25,11 +25,12 @@ import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; -import org.springframework.web.socket.sockjs.AbstractSockJsSession; -import org.springframework.web.socket.sockjs.SockJsMessageCodec; -import org.springframework.web.socket.sockjs.TransportErrorException; -import org.springframework.web.socket.sockjs.TransportHandler; -import org.springframework.web.socket.sockjs.TransportType; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.sockjs.SockJsProcessingException; +import org.springframework.web.socket.sockjs.support.frame.SockJsMessageCodec; +import org.springframework.web.socket.sockjs.transport.TransportHandler; +import org.springframework.web.socket.sockjs.transport.TransportType; /** * A {@link TransportHandler} that receives messages over HTTP. @@ -48,22 +49,22 @@ public class JsonpTransportHandler extends AbstractHttpReceivingTransportHandler @Override public void handleRequestInternal(ServerHttpRequest request, ServerHttpResponse response, - AbstractSockJsSession sockJsSession) throws TransportErrorException { + WebSocketHandler webSocketHandler, WebSocketSession webSocketSession) throws SockJsProcessingException { - super.handleRequestInternal(request, response, sockJsSession); + super.handleRequestInternal(request, response, webSocketHandler, webSocketSession); try { response.getBody().write("ok".getBytes("UTF-8")); } catch (Throwable t) { - throw new TransportErrorException("Failed to write response body", t, sockJsSession.getId()); + throw new SockJsProcessingException("Failed to write response body", t, webSocketSession.getId()); } } @Override protected String[] readMessages(ServerHttpRequest request) throws IOException { - SockJsMessageCodec messageCodec = getSockJsConfig().getMessageCodecRequired(); + SockJsMessageCodec messageCodec = getSockJsServiceConfig().getMessageCodec(); MediaType contentType = request.getHeaders().getContentType(); if ((contentType != null) && MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) { diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsSessionFactory.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/SockJsSessionFactory.java similarity index 84% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsSessionFactory.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/SockJsSessionFactory.java index 0feee2d76c..06d54ae09e 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsSessionFactory.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/SockJsSessionFactory.java @@ -14,9 +14,11 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs; +package org.springframework.web.socket.sockjs.transport.handler; import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.sockjs.transport.TransportHandler; +import org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession; /** * A factory for creating a SockJS session. {@link TransportHandler}s typically also serve diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/SockJsWebSocketHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandler.java similarity index 83% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/SockJsWebSocketHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandler.java index 4f1d3e1e95..ef8a64b502 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/SockJsWebSocketHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.util.concurrent.atomic.AtomicInteger; @@ -24,7 +24,8 @@ import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.adapter.TextWebSocketHandlerAdapter; -import org.springframework.web.socket.sockjs.SockJsConfiguration; +import org.springframework.web.socket.sockjs.transport.session.SockJsServiceConfig; +import org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession; /** * An implementation of {@link WebSocketHandler} that adds SockJS messages frames, sends @@ -43,26 +44,26 @@ import org.springframework.web.socket.sockjs.SockJsConfiguration; */ public class SockJsWebSocketHandler extends TextWebSocketHandlerAdapter { - private final SockJsConfiguration sockJsConfig; + private final SockJsServiceConfig sockJsServiceConfig; private final WebSocketServerSockJsSession session; private final AtomicInteger sessionCount = new AtomicInteger(0); - public SockJsWebSocketHandler(SockJsConfiguration config, + public SockJsWebSocketHandler(SockJsServiceConfig sockJsServiceConfig, WebSocketHandler webSocketHandler, WebSocketServerSockJsSession session) { - Assert.notNull(config, "config must not be null"); + Assert.notNull(sockJsServiceConfig, "sockJsServiceConfig must not be null"); Assert.notNull(webSocketHandler, "webSocketHandler must not be null"); Assert.notNull(session, "session must not be null"); - this.sockJsConfig = config; + this.sockJsServiceConfig = sockJsServiceConfig; this.session = session; } - protected SockJsConfiguration getSockJsConfig() { - return this.sockJsConfig; + protected SockJsServiceConfig getSockJsConfig() { + return this.sockJsServiceConfig; } @Override diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandlerSupport.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/TransportHandlerSupport.java similarity index 68% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandlerSupport.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/TransportHandlerSupport.java index 3dfe2e6a06..7b0c737faa 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandlerSupport.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/TransportHandlerSupport.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.web.socket.sockjs.SockJsConfiguration; +import org.springframework.web.socket.sockjs.transport.session.SockJsServiceConfig; /** @@ -29,16 +29,15 @@ public abstract class TransportHandlerSupport { protected final Log logger = LogFactory.getLog(this.getClass()); - private SockJsConfiguration sockJsConfig; + private SockJsServiceConfig sockJsServiceConfig; - public void setSockJsConfiguration(SockJsConfiguration sockJsConfig) { - this.sockJsConfig = sockJsConfig; + public void setSockJsServiceConfiguration(SockJsServiceConfig sockJsConfig) { + this.sockJsServiceConfig = sockJsConfig; } - public SockJsConfiguration getSockJsConfig() { - return this.sockJsConfig; + public SockJsServiceConfig getSockJsServiceConfig() { + return this.sockJsServiceConfig; } - } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/WebSocketTransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/WebSocketTransportHandler.java similarity index 67% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/WebSocketTransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/WebSocketTransportHandler.java index 5b53f430ee..7bb2b1c8b5 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/WebSocketTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/WebSocketTransportHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.io.IOException; @@ -22,12 +22,13 @@ import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.util.Assert; import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.server.HandshakeHandler; -import org.springframework.web.socket.sockjs.AbstractSockJsSession; -import org.springframework.web.socket.sockjs.SockJsSessionFactory; -import org.springframework.web.socket.sockjs.TransportErrorException; -import org.springframework.web.socket.sockjs.TransportHandler; -import org.springframework.web.socket.sockjs.TransportType; +import org.springframework.web.socket.sockjs.SockJsProcessingException; +import org.springframework.web.socket.sockjs.transport.TransportHandler; +import org.springframework.web.socket.sockjs.transport.TransportType; +import org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession; +import org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession; /** * A WebSocket {@link TransportHandler}. Uses {@link SockJsWebSocketHandler} and @@ -58,20 +59,20 @@ public class WebSocketTransportHandler extends TransportHandlerSupport @Override public AbstractSockJsSession createSession(String sessionId, WebSocketHandler webSocketHandler) { - return new WebSocketServerSockJsSession(sessionId, getSockJsConfig(), webSocketHandler); + return new WebSocketServerSockJsSession(sessionId, getSockJsServiceConfig(), webSocketHandler); } @Override public void handleRequest(ServerHttpRequest request, ServerHttpResponse response, - WebSocketHandler webSocketHandler, AbstractSockJsSession session) throws TransportErrorException { + WebSocketHandler wsHandler, WebSocketSession wsSession) throws SockJsProcessingException { try { - WebSocketServerSockJsSession wsSession = (WebSocketServerSockJsSession) session; - WebSocketHandler sockJsWrapper = new SockJsWebSocketHandler(getSockJsConfig(), webSocketHandler, wsSession); - this.handshakeHandler.doHandshake(request, response, sockJsWrapper); + WebSocketServerSockJsSession sockJsSession = (WebSocketServerSockJsSession) wsSession; + WebSocketHandler sockJsHandler = new SockJsWebSocketHandler(getSockJsServiceConfig(), wsHandler, sockJsSession); + this.handshakeHandler.doHandshake(request, response, sockJsHandler); } catch (Throwable t) { - throw new TransportErrorException("Failed to start handshake request", t, session.getId()); + throw new SockJsProcessingException("Failed to start handshake request", t, wsSession.getId()); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/XhrPollingTransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/XhrPollingTransportHandler.java similarity index 72% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/XhrPollingTransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/XhrPollingTransportHandler.java index 3f26872a47..ed59a339e2 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/XhrPollingTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/XhrPollingTransportHandler.java @@ -14,17 +14,18 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.nio.charset.Charset; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.SockJsFrame.DefaultFrameFormat; -import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat; -import org.springframework.web.socket.sockjs.TransportHandler; -import org.springframework.web.socket.sockjs.TransportType; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.DefaultFrameFormat; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat; +import org.springframework.web.socket.sockjs.transport.TransportHandler; +import org.springframework.web.socket.sockjs.transport.TransportType; +import org.springframework.web.socket.sockjs.transport.session.PollingSockJsSession; /** * A {@link TransportHandler} based on XHR (long) polling. @@ -51,7 +52,7 @@ public class XhrPollingTransportHandler extends AbstractHttpSendingTransportHand @Override public PollingSockJsSession createSession(String sessionId, WebSocketHandler handler) { - return new PollingSockJsSession(sessionId, getSockJsConfig(), handler); + return new PollingSockJsSession(sessionId, getSockJsServiceConfig(), handler); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/XhrStreamingTransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/XhrStreamingTransportHandler.java similarity index 71% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/XhrStreamingTransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/XhrStreamingTransportHandler.java index 2e38c136fe..307471c705 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/XhrStreamingTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/XhrStreamingTransportHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.io.IOException; import java.nio.charset.Charset; @@ -22,11 +22,12 @@ import java.nio.charset.Charset; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.SockJsConfiguration; -import org.springframework.web.socket.sockjs.SockJsFrame.DefaultFrameFormat; -import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat; -import org.springframework.web.socket.sockjs.TransportHandler; -import org.springframework.web.socket.sockjs.TransportType; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.DefaultFrameFormat; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat; +import org.springframework.web.socket.sockjs.transport.TransportHandler; +import org.springframework.web.socket.sockjs.transport.TransportType; +import org.springframework.web.socket.sockjs.transport.session.SockJsServiceConfig; +import org.springframework.web.socket.sockjs.transport.session.StreamingSockJsSession; /** * A {@link TransportHandler} that sends messages over an HTTP streaming request. @@ -49,7 +50,7 @@ public class XhrStreamingTransportHandler extends AbstractHttpSendingTransportHa @Override public StreamingSockJsSession createSession(String sessionId, WebSocketHandler handler) { - return new XhrStreamingSockJsSession(sessionId, getSockJsConfig(), handler); + return new XhrStreamingSockJsSession(sessionId, getSockJsServiceConfig(), handler); } @Override @@ -60,7 +61,7 @@ public class XhrStreamingTransportHandler extends AbstractHttpSendingTransportHa private final class XhrStreamingSockJsSession extends StreamingSockJsSession { - private XhrStreamingSockJsSession(String sessionId, SockJsConfiguration config, WebSocketHandler handler) { + private XhrStreamingSockJsSession(String sessionId, SockJsServiceConfig config, WebSocketHandler handler) { super(sessionId, config, handler); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/XhrTransportHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/XhrTransportHandler.java similarity index 80% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/XhrTransportHandler.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/XhrTransportHandler.java index fdbc5f8893..6965dee961 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/XhrTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/XhrTransportHandler.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.io.IOException; import org.springframework.http.HttpStatus; import org.springframework.http.server.ServerHttpRequest; -import org.springframework.web.socket.sockjs.TransportHandler; -import org.springframework.web.socket.sockjs.TransportType; +import org.springframework.web.socket.sockjs.transport.TransportHandler; +import org.springframework.web.socket.sockjs.transport.TransportType; /** * A {@link TransportHandler} that receives messages over HTTP. @@ -38,7 +38,7 @@ public class XhrTransportHandler extends AbstractHttpReceivingTransportHandler { @Override protected String[] readMessages(ServerHttpRequest request) throws IOException { - return getSockJsConfig().getMessageCodecRequired().decodeInputStream(request.getBody()); + return getSockJsServiceConfig().getMessageCodec().decodeInputStream(request.getBody()); } @Override diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/package-info.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/package-info.java new file mode 100644 index 0000000000..09a3ba4599 --- /dev/null +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/** + * {@link org.springframework.web.socket.sockjs.transport.TransportHandler} + * implementation classes as well as a concrete + * {@link org.springframework.web.socket.sockjs.SockJsService}. + */ +package org.springframework.web.socket.sockjs.transport.handler; + diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/package-info.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/package-info.java index 55c92a22eb..4dd87fef92 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/package-info.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/package-info.java @@ -16,11 +16,11 @@ /** * Server-side support for SockJS transports including - * {@link org.springframework.web.socket.sockjs.TransportHandler} implementations + * {@link org.springframework.web.socket.sockjs.transport.TransportHandler} implementations * for processing incoming requests, their - * {@link org.springframework.web.socket.sockjs.AbstractSockJsSession session} counterparts for + * {@link org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession session} counterparts for * sending messages over the various transports, and - * {@link org.springframework.web.socket.sockjs.transport.DefaultSockJsService}. + * {@link org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService}. */ package org.springframework.web.socket.sockjs.transport; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/AbstractHttpSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java similarity index 85% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/AbstractHttpSockJsSession.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java index e5e9482713..983f2197c2 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/AbstractHttpSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.session; import java.io.IOException; import java.util.concurrent.ArrayBlockingQueue; @@ -26,11 +26,9 @@ import org.springframework.http.server.ServerHttpResponse; import org.springframework.util.Assert; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.AbstractSockJsSession; -import org.springframework.web.socket.sockjs.SockJsConfiguration; -import org.springframework.web.socket.sockjs.SockJsFrame; -import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat; -import org.springframework.web.socket.sockjs.TransportErrorException; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat; +import org.springframework.web.socket.sockjs.SockJsProcessingException; import org.springframework.web.socket.support.ExceptionWebSocketHandlerDecorator; /** @@ -52,7 +50,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { private String protocol; - public AbstractHttpSockJsSession(String sessionId, SockJsConfiguration config, WebSocketHandler handler) { + public AbstractHttpSockJsSession(String sessionId, SockJsServiceConfig config, WebSocketHandler handler) { super(sessionId, config, handler); } @@ -76,7 +74,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { } public synchronized void setInitialRequest(ServerHttpRequest request, ServerHttpResponse response, - FrameFormat frameFormat) throws TransportErrorException { + FrameFormat frameFormat) throws SockJsProcessingException { try { udpateRequest(request, response, frameFormat); @@ -85,7 +83,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { } catch (Throwable t) { tryCloseWithSockJsTransportError(t, null); - throw new TransportErrorException("Failed open SockJS session", t, getId()); + throw new SockJsProcessingException("Failed open SockJS session", t, getId()); } try { delegateConnectionEstablished(); @@ -99,7 +97,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { } public synchronized void setLongPollingRequest(ServerHttpRequest request, ServerHttpResponse response, - FrameFormat frameFormat) throws TransportErrorException { + FrameFormat frameFormat) throws SockJsProcessingException { try { udpateRequest(request, response, frameFormat); @@ -110,7 +108,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { writeFrame(SockJsFrame.closeFrameGoAway()); } catch (IOException ex) { - throw new TransportErrorException("Failed to send SockJS close frame", ex, getId()); + throw new SockJsProcessingException("Failed to send SockJS close frame", ex, getId()); } return; } @@ -123,7 +121,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { } catch (Throwable t) { tryCloseWithSockJsTransportError(t, null); - throw new TransportErrorException("Failed to start long running request and flush messages", t, getId()); + throw new SockJsProcessingException("Failed to start long running request and flush messages", t, getId()); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/AbstractSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java similarity index 88% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/AbstractSockJsSession.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java index 31d392b06e..f04f27f76c 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/AbstractSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs; +package org.springframework.web.socket.sockjs.transport.session; import java.io.EOFException; import java.io.IOException; @@ -33,6 +33,8 @@ import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.WebSocketMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.adapter.ConfigurableWebSocketSession; +import org.springframework.web.socket.sockjs.SockJsProcessingException; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame; /** * An abstract base class SockJS sessions implementing {@link WebSocketSession}. @@ -55,7 +57,7 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess private Principal principal; - private final SockJsConfiguration sockJsConfig; + private final SockJsServiceConfig sockJsServiceConfig; private final WebSocketHandler handler; @@ -70,16 +72,16 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess /** * @param sessionId the session ID - * @param config the sockJS configuration - * @param webSocketHandler the recipient of SockJS messages + * @param config SockJS service configuration options + * @param wsHandler the recipient of SockJS messages */ - public AbstractSockJsSession(String sessionId, SockJsConfiguration config, WebSocketHandler webSocketHandler) { + public AbstractSockJsSession(String sessionId, SockJsServiceConfig config, WebSocketHandler wsHandler) { Assert.notNull(sessionId, "sessionId is required"); Assert.notNull(config, "sockJsConfig is required"); - Assert.notNull(webSocketHandler, "webSocketHandler is required"); + Assert.notNull(wsHandler, "webSocketHandler is required"); this.id = sessionId; - this.sockJsConfig = config; - this.handler = webSocketHandler; + this.sockJsServiceConfig = config; + this.handler = wsHandler; } @Override @@ -132,8 +134,8 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess this.principal = principal; } - public SockJsConfiguration getSockJsConfig() { - return this.sockJsConfig; + public SockJsServiceConfig getSockJsServiceConfig() { + return this.sockJsServiceConfig; } public boolean isNew() { @@ -318,7 +320,7 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess logger.warn("Terminating connection due to failure to send message: " + ex.getMessage()); disconnect(CloseStatus.SERVER_ERROR); close(CloseStatus.SERVER_ERROR); - throw new TransportErrorException("Failed to write " + frame, ex, this.getId()); + throw new SockJsProcessingException("Failed to write " + frame, ex, this.getId()); } } @@ -332,13 +334,13 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess } protected void scheduleHeartbeat() { - Assert.state(this.sockJsConfig.getTaskScheduler() != null, "heartbeatScheduler not configured"); + Assert.state(this.sockJsServiceConfig.getTaskScheduler() != null, "heartbeatScheduler not configured"); cancelHeartbeat(); if (!isActive()) { return; } - Date time = new Date(System.currentTimeMillis() + this.sockJsConfig.getHeartbeatTime()); - this.heartbeatTask = this.sockJsConfig.getTaskScheduler().schedule(new Runnable() { + Date time = new Date(System.currentTimeMillis() + this.sockJsServiceConfig.getHeartbeatTime()); + this.heartbeatTask = this.sockJsServiceConfig.getTaskScheduler().schedule(new Runnable() { public void run() { try { sendHeartbeat(); @@ -349,7 +351,7 @@ public abstract class AbstractSockJsSession implements ConfigurableWebSocketSess } }, time); if (logger.isTraceEnabled()) { - logger.trace("Scheduled heartbeat after " + this.sockJsConfig.getHeartbeatTime()/1000 + " seconds"); + logger.trace("Scheduled heartbeat after " + this.sockJsServiceConfig.getHeartbeatTime()/1000 + " seconds"); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/PollingSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/PollingSockJsSession.java similarity index 75% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/PollingSockJsSession.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/PollingSockJsSession.java index 13f04c822b..8de55152d8 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/PollingSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/PollingSockJsSession.java @@ -14,14 +14,13 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.session; import java.io.IOException; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.SockJsConfiguration; -import org.springframework.web.socket.sockjs.SockJsFrame; -import org.springframework.web.socket.sockjs.SockJsMessageCodec; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame; +import org.springframework.web.socket.sockjs.support.frame.SockJsMessageCodec; /** * A SockJS session for use with polling HTTP transports. @@ -30,7 +29,7 @@ import org.springframework.web.socket.sockjs.SockJsMessageCodec; */ public class PollingSockJsSession extends AbstractHttpSockJsSession { - public PollingSockJsSession(String sessionId, SockJsConfiguration config, WebSocketHandler handler) { + public PollingSockJsSession(String sessionId, SockJsServiceConfig config, WebSocketHandler handler) { super(sessionId, config, handler); } @@ -42,7 +41,7 @@ public class PollingSockJsSession extends AbstractHttpSockJsSession { String[] messages = getMessageCache().toArray(new String[getMessageCache().size()]); getMessageCache().clear(); - SockJsMessageCodec messageCodec = getSockJsConfig().getMessageCodecRequired(); + SockJsMessageCodec messageCodec = getSockJsServiceConfig().getMessageCodec(); SockJsFrame frame = SockJsFrame.messageFrame(messageCodec, messages); writeFrame(frame); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/SockJsServiceConfig.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/SockJsServiceConfig.java new file mode 100644 index 0000000000..0d196c9632 --- /dev/null +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/SockJsServiceConfig.java @@ -0,0 +1,40 @@ +/* + * 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.web.socket.sockjs.transport.session; + +import org.springframework.scheduling.TaskScheduler; +import org.springframework.web.socket.sockjs.SockJsService; +import org.springframework.web.socket.sockjs.support.frame.SockJsMessageCodec; + +/** + * Provides transport handling code with access to the {@link SockJsService} configuration + * options they need to have access to. Mainly for internal use. + * + * @author Rossen Stoyanchev + * @since 4.0 + */ +public interface SockJsServiceConfig { + + int getStreamBytesLimit(); + + long getHeartbeatTime(); + + TaskScheduler getTaskScheduler(); + + SockJsMessageCodec getMessageCodec(); + +} diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/StreamingSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/StreamingSockJsSession.java similarity index 77% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/StreamingSockJsSession.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/StreamingSockJsSession.java index 3ce2ec9b2d..2cf2813d9d 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/StreamingSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/StreamingSockJsSession.java @@ -14,18 +14,17 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.session; import java.io.IOException; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.SockJsConfiguration; -import org.springframework.web.socket.sockjs.SockJsFrame; -import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat; -import org.springframework.web.socket.sockjs.SockJsMessageCodec; -import org.springframework.web.socket.sockjs.TransportErrorException; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame; +import org.springframework.web.socket.sockjs.support.frame.SockJsMessageCodec; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat; +import org.springframework.web.socket.sockjs.SockJsProcessingException; /** * A SockJS session for use with streaming HTTP transports. @@ -37,14 +36,14 @@ public class StreamingSockJsSession extends AbstractHttpSockJsSession { private int byteCount; - public StreamingSockJsSession(String sessionId, SockJsConfiguration config, WebSocketHandler handler) { + public StreamingSockJsSession(String sessionId, SockJsServiceConfig config, WebSocketHandler handler) { super(sessionId, config, handler); } @Override public synchronized void setInitialRequest(ServerHttpRequest request, ServerHttpResponse response, - FrameFormat frameFormat) throws TransportErrorException { + FrameFormat frameFormat) throws SockJsProcessingException { super.setInitialRequest(request, response, frameFormat); @@ -61,7 +60,7 @@ public class StreamingSockJsSession extends AbstractHttpSockJsSession { do { String message = getMessageCache().poll(); - SockJsMessageCodec messageCodec = getSockJsConfig().getMessageCodecRequired(); + SockJsMessageCodec messageCodec = getSockJsServiceConfig().getMessageCodec(); SockJsFrame frame = SockJsFrame.messageFrame(messageCodec, message); writeFrame(frame); @@ -70,7 +69,7 @@ public class StreamingSockJsSession extends AbstractHttpSockJsSession { logger.trace(this.byteCount + " bytes written so far, " + getMessageCache().size() + " more messages not flushed"); } - if (this.byteCount >= getSockJsConfig().getStreamBytesLimit()) { + if (this.byteCount >= getSockJsServiceConfig().getStreamBytesLimit()) { if (logger.isTraceEnabled()) { logger.trace("Streamed bytes limit reached. Recycling current request"); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/WebSocketServerSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/WebSocketServerSockJsSession.java similarity index 84% rename from spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/WebSocketServerSockJsSession.java rename to spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/WebSocketServerSockJsSession.java index d1f873b433..5d2f8f34e1 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/WebSocketServerSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/WebSocketServerSockJsSession.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.session; import java.io.IOException; @@ -23,10 +23,8 @@ import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.sockjs.AbstractSockJsSession; -import org.springframework.web.socket.sockjs.SockJsConfiguration; -import org.springframework.web.socket.sockjs.SockJsFrame; -import org.springframework.web.socket.sockjs.SockJsMessageCodec; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame; +import org.springframework.web.socket.sockjs.support.frame.SockJsMessageCodec; /** * A SockJS session for use with the WebSocket transport. @@ -39,7 +37,7 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession { private WebSocketSession webSocketSession; - public WebSocketServerSockJsSession(String sessionId, SockJsConfiguration config, WebSocketHandler handler) { + public WebSocketServerSockJsSession(String sessionId, SockJsServiceConfig config, WebSocketHandler handler) { super(sessionId, config, handler); } @@ -85,7 +83,7 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession { } String[] messages; try { - messages = getSockJsConfig().getMessageCodecRequired().decode(payload); + messages = getSockJsServiceConfig().getMessageCodec().decode(payload); } catch (IOException ex) { logger.error("Broken data received. Terminating WebSocket connection abruptly", ex); @@ -98,7 +96,7 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession { @Override public void sendMessageInternal(String message) throws IOException { cancelHeartbeat(); - SockJsMessageCodec messageCodec = getSockJsConfig().getMessageCodecRequired(); + SockJsMessageCodec messageCodec = getSockJsServiceConfig().getMessageCodec(); SockJsFrame frame = SockJsFrame.messageFrame(messageCodec, message); writeFrame(frame); scheduleHeartbeat(); diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/package-info.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/package-info.java new file mode 100644 index 0000000000..7e20e9a6bb --- /dev/null +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/package-info.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * SockJS specific implementations of + * {@link org.springframework.web.socket.WebSocketSession}. + */ +package org.springframework.web.socket.sockjs.transport.session; + diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/AbstractSockJsServiceTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/support/AbstractSockJsServiceTests.java similarity index 91% rename from spring-websocket/src/test/java/org/springframework/web/socket/sockjs/AbstractSockJsServiceTests.java rename to spring-websocket/src/test/java/org/springframework/web/socket/sockjs/support/AbstractSockJsServiceTests.java index d72b3934a0..deabe9bf00 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/AbstractSockJsServiceTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/support/AbstractSockJsServiceTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs; +package org.springframework.web.socket.sockjs.support; import java.io.IOException; @@ -27,6 +27,8 @@ import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.web.socket.AbstractHttpRequestTests; import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.sockjs.SockJsProcessingException; +import org.springframework.web.socket.sockjs.transport.TransportType; import static org.junit.Assert.*; @@ -77,7 +79,7 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests { handleRequest("GET", "/a/server/session/xhr", HttpStatus.OK); assertEquals("session", this.service.sessionId); - assertEquals(TransportType.XHR, this.service.transportType); + assertEquals(TransportType.XHR.value(), this.service.transport); assertSame(this.handler, this.service.handler); this.service.setValidSockJsPrefixes("/b"); @@ -96,7 +98,7 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests { handleRequest("GET", "/a/server/session/xhr", HttpStatus.OK); assertEquals("session", this.service.sessionId); - assertEquals(TransportType.XHR, this.service.transportType); + assertEquals(TransportType.XHR.value(), this.service.transport); assertSame(this.handler, this.service.handler); } @@ -107,7 +109,7 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests { handleRequest("GET", "/a/server/session/xhr", HttpStatus.OK); assertEquals("session", this.service.sessionId); - assertEquals(TransportType.XHR, this.service.transportType); + assertEquals(TransportType.XHR.value(), this.service.transport); assertSame(this.handler, this.service.handler); } @@ -216,7 +218,7 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests { private String sessionId; - private TransportType transportType; + private String transport; private WebSocketHandler handler; @@ -224,11 +226,6 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests { super(scheduler); } - @Override - public SockJsMessageCodec getMessageCodecRequired() { - throw new UnsupportedOperationException(); - } - @Override protected void handleRawWebSocketRequest(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler) throws IOException { @@ -237,15 +234,19 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests { } @Override - protected void handleTransportRequest(ServerHttpRequest request, - ServerHttpResponse response, String sessionId, - TransportType transportType, WebSocketHandler handler) - throws IOException, TransportErrorException { + protected void handleTransportRequest(ServerHttpRequest request, ServerHttpResponse response, + WebSocketHandler handler, String sessionId, String transport) + throws IOException, SockJsProcessingException { this.sessionId = sessionId; - this.transportType = transportType; + this.transport = transport; this.handler = handler; } + + @Override + protected boolean isValidTransportType(String transportType) { + return TransportType.fromValue(transportType) != null; + } } } diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/TransportTypeTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/TransportTypeTests.java similarity index 91% rename from spring-websocket/src/test/java/org/springframework/web/socket/sockjs/TransportTypeTests.java rename to spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/TransportTypeTests.java index 1e06d1d66e..82c118d4df 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/TransportTypeTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/TransportTypeTests.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs; +package org.springframework.web.socket.sockjs.transport; import org.junit.Test; +import org.springframework.web.socket.sockjs.transport.TransportType; import static org.junit.Assert.*; diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/DefaultSockJsServiceTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/DefaultSockJsServiceTests.java similarity index 77% rename from spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/DefaultSockJsServiceTests.java rename to spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/DefaultSockJsServiceTests.java index 2849f1f6ee..c91fe926ff 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/DefaultSockJsServiceTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/DefaultSockJsServiceTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.util.Collections; import java.util.HashSet; @@ -29,14 +29,15 @@ import org.springframework.http.server.ServerHttpResponse; import org.springframework.scheduling.TaskScheduler; import org.springframework.web.socket.AbstractHttpRequestTests; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.AbstractSockJsSession; -import org.springframework.web.socket.sockjs.SockJsConfiguration; -import org.springframework.web.socket.sockjs.SockJsSessionFactory; -import org.springframework.web.socket.sockjs.StubSockJsConfig; -import org.springframework.web.socket.sockjs.TestSockJsSession; -import org.springframework.web.socket.sockjs.TransportErrorException; -import org.springframework.web.socket.sockjs.TransportHandler; -import org.springframework.web.socket.sockjs.TransportType; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.sockjs.SockJsProcessingException; +import org.springframework.web.socket.sockjs.transport.TransportHandler; +import org.springframework.web.socket.sockjs.transport.TransportType; +import org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService; +import org.springframework.web.socket.sockjs.transport.handler.SockJsSessionFactory; +import org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession; +import org.springframework.web.socket.sockjs.transport.session.StubSockJsServiceConfig; +import org.springframework.web.socket.sockjs.transport.session.TestSockJsSession; import static org.junit.Assert.*; import static org.mockito.Matchers.*; @@ -83,7 +84,7 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests { WebSocketHandler webSocketHandler = mock(WebSocketHandler.class); DefaultSockJsService service = new DefaultSockJsService(taskScheduler, transportHandlers); - service.handleTransportRequest(this.request, this.response, "123", TransportType.XHR, webSocketHandler); + service.handleTransportRequest(this.request, this.response, webSocketHandler, "123", TransportType.XHR.value()); assertEquals(200, this.servletResponse.getStatus()); assertNotNull(xhrHandler.session); @@ -107,7 +108,7 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests { Set transportHandlers = Collections.singleton(xhrHandler); DefaultSockJsService service = new DefaultSockJsService(taskScheduler, transportHandlers); - service.handleTransportRequest(this.request, this.response, "123", TransportType.XHR, null); + service.handleTransportRequest(this.request, this.response, null, "123", TransportType.XHR.value()); assertEquals(204, this.servletResponse.getStatus()); assertEquals("*", this.response.getHeaders().getFirst("Access-Control-Allow-Origin")); @@ -122,7 +123,7 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests { Set transportHandlers = new HashSet<>(); DefaultSockJsService service = new DefaultSockJsService(mock(TaskScheduler.class), transportHandlers); - service.handleTransportRequest(this.request, this.response, "123", TransportType.XHR, null); + service.handleTransportRequest(this.request, this.response, null, "123", TransportType.XHR.value()); assertEquals(404, this.servletResponse.getStatus()); } @@ -135,20 +136,20 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests { Set transportHandlers = new HashSet<>(); transportHandlers.add(new StubXhrTransportHandler()); transportHandlers.add(new StubXhrSendTransportHandler()); - WebSocketHandler webSocketHandler = mock(WebSocketHandler.class); + WebSocketHandler wsHandler = mock(WebSocketHandler.class); DefaultSockJsService service = new DefaultSockJsService(mock(TaskScheduler.class), transportHandlers); - service.handleTransportRequest(this.request, this.response, "123", TransportType.XHR_SEND, webSocketHandler); + service.handleTransportRequest(this.request, this.response, wsHandler, "123", TransportType.XHR_SEND.value()); assertEquals(404, this.servletResponse.getStatus()); // dropped (no session) resetResponse(); - service.handleTransportRequest(this.request, this.response, "123", TransportType.XHR, webSocketHandler); + service.handleTransportRequest(this.request, this.response, wsHandler, "123", TransportType.XHR.value()); assertEquals(200, this.servletResponse.getStatus()); resetResponse(); - service.handleTransportRequest(this.request, this.response, "123", TransportType.XHR_SEND, webSocketHandler); + service.handleTransportRequest(this.request, this.response, wsHandler, "123", TransportType.XHR_SEND.value()); assertEquals(200, this.servletResponse.getStatus()); } @@ -158,20 +159,16 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests { WebSocketHandler webSocketHandler; - AbstractSockJsSession session; + WebSocketSession session; @Override public TransportType getTransportType() { return TransportType.XHR; } - @Override - public void setSockJsConfiguration(SockJsConfiguration sockJsConfig) { - } - @Override public void handleRequest(ServerHttpRequest request, ServerHttpResponse response, - WebSocketHandler handler, AbstractSockJsSession session) throws TransportErrorException { + WebSocketHandler handler, WebSocketSession session) throws SockJsProcessingException { this.webSocketHandler = handler; this.session = session; @@ -179,7 +176,7 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests { @Override public AbstractSockJsSession createSession(String sessionId, WebSocketHandler webSocketHandler) { - return new TestSockJsSession(sessionId, new StubSockJsConfig(), webSocketHandler); + return new TestSockJsSession(sessionId, new StubSockJsServiceConfig(), webSocketHandler); } } @@ -191,13 +188,9 @@ public class DefaultSockJsServiceTests extends AbstractHttpRequestTests { return TransportType.XHR_SEND; } - @Override - public void setSockJsConfiguration(SockJsConfiguration sockJsConfig) { - } - @Override public void handleRequest(ServerHttpRequest request, ServerHttpResponse response, - WebSocketHandler handler, AbstractSockJsSession session) throws TransportErrorException { + WebSocketHandler handler, WebSocketSession session) throws SockJsProcessingException { if (session == null) { response.setStatusCode(HttpStatus.NOT_FOUND); diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/HttpReceivingTransportHandlerTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/HttpReceivingTransportHandlerTests.java similarity index 82% rename from spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/HttpReceivingTransportHandlerTests.java rename to spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/HttpReceivingTransportHandlerTests.java index 816bda130a..b4c7d2f535 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/HttpReceivingTransportHandlerTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/HttpReceivingTransportHandlerTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import org.junit.Before; import org.junit.Test; @@ -23,10 +23,13 @@ import org.springframework.web.socket.AbstractHttpRequestTests; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.AbstractSockJsSession; -import org.springframework.web.socket.sockjs.StubSockJsConfig; -import org.springframework.web.socket.sockjs.TestSockJsSession; -import org.springframework.web.socket.sockjs.TransportErrorException; +import org.springframework.web.socket.sockjs.SockJsProcessingException; +import org.springframework.web.socket.sockjs.transport.handler.AbstractHttpReceivingTransportHandler; +import org.springframework.web.socket.sockjs.transport.handler.JsonpTransportHandler; +import org.springframework.web.socket.sockjs.transport.handler.XhrTransportHandler; +import org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession; +import org.springframework.web.socket.sockjs.transport.session.StubSockJsServiceConfig; +import org.springframework.web.socket.sockjs.transport.session.TestSockJsSession; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -105,7 +108,7 @@ public class HttpReceivingTransportHandlerTests extends AbstractHttpRequestTest @Test public void delegateMessageException() throws Exception { - StubSockJsConfig sockJsConfig = new StubSockJsConfig(); + StubSockJsServiceConfig sockJsConfig = new StubSockJsServiceConfig(); this.servletRequest.setContent("[\"x\"]".getBytes("UTF-8")); @@ -117,11 +120,11 @@ public class HttpReceivingTransportHandlerTests extends AbstractHttpRequestTest try { XhrTransportHandler transportHandler = new XhrTransportHandler(); - transportHandler.setSockJsConfiguration(sockJsConfig); + transportHandler.setSockJsServiceConfiguration(sockJsConfig); transportHandler.handleRequest(this.request, this.response, webSocketHandler, session); fail("Expected exception"); } - catch (TransportErrorException ex) { + catch (SockJsProcessingException ex) { assertEquals(CloseStatus.SERVER_ERROR, session.getStatus()); } } @@ -131,9 +134,9 @@ public class HttpReceivingTransportHandlerTests extends AbstractHttpRequestTest throws Exception { WebSocketHandler webSocketHandler = mock(WebSocketHandler.class); - AbstractSockJsSession session = new TestSockJsSession("1", new StubSockJsConfig(), webSocketHandler); + AbstractSockJsSession session = new TestSockJsSession("1", new StubSockJsServiceConfig(), webSocketHandler); - transportHandler.setSockJsConfiguration(new StubSockJsConfig()); + transportHandler.setSockJsServiceConfiguration(new StubSockJsServiceConfig()); transportHandler.handleRequest(this.request, this.response, webSocketHandler, session); assertEquals("text/plain;charset=UTF-8", this.response.getHeaders().getContentType().toString()); @@ -145,7 +148,7 @@ public class HttpReceivingTransportHandlerTests extends AbstractHttpRequestTest resetResponse(); WebSocketHandler webSocketHandler = mock(WebSocketHandler.class); - AbstractSockJsSession session = new TestSockJsSession("1", new StubSockJsConfig(), webSocketHandler); + AbstractSockJsSession session = new TestSockJsSession("1", new StubSockJsServiceConfig(), webSocketHandler); new XhrTransportHandler().handleRequest(this.request, this.response, webSocketHandler, session); diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/HttpSendingTransportHandlerTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/HttpSendingTransportHandlerTests.java similarity index 81% rename from spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/HttpSendingTransportHandlerTests.java rename to spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/HttpSendingTransportHandlerTests.java index 01f4afc301..e42177e30e 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/HttpSendingTransportHandlerTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/HttpSendingTransportHandlerTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.handler; import java.sql.Date; @@ -23,10 +23,18 @@ import org.junit.Test; import org.springframework.scheduling.TaskScheduler; import org.springframework.web.socket.AbstractHttpRequestTests; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.AbstractSockJsSession; -import org.springframework.web.socket.sockjs.SockJsFrame; -import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat; -import org.springframework.web.socket.sockjs.StubSockJsConfig; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat; +import org.springframework.web.socket.sockjs.transport.handler.AbstractHttpSendingTransportHandler; +import org.springframework.web.socket.sockjs.transport.handler.EventSourceTransportHandler; +import org.springframework.web.socket.sockjs.transport.handler.HtmlFileTransportHandler; +import org.springframework.web.socket.sockjs.transport.handler.JsonpPollingTransportHandler; +import org.springframework.web.socket.sockjs.transport.handler.XhrPollingTransportHandler; +import org.springframework.web.socket.sockjs.transport.handler.XhrStreamingTransportHandler; +import org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession; +import org.springframework.web.socket.sockjs.transport.session.PollingSockJsSession; +import org.springframework.web.socket.sockjs.transport.session.StreamingSockJsSession; +import org.springframework.web.socket.sockjs.transport.session.StubSockJsServiceConfig; import static org.junit.Assert.*; import static org.mockito.Matchers.*; @@ -41,7 +49,7 @@ public class HttpSendingTransportHandlerTests extends AbstractHttpRequestTests private WebSocketHandler webSocketHandler; - private StubSockJsConfig sockJsConfig; + private StubSockJsServiceConfig sockJsConfig; private TaskScheduler taskScheduler; @@ -54,7 +62,7 @@ public class HttpSendingTransportHandlerTests extends AbstractHttpRequestTests this.webSocketHandler = mock(WebSocketHandler.class); this.taskScheduler = mock(TaskScheduler.class); - this.sockJsConfig = new StubSockJsConfig(); + this.sockJsConfig = new StubSockJsServiceConfig(); this.sockJsConfig.setTaskScheduler(this.taskScheduler); } @@ -62,7 +70,7 @@ public class HttpSendingTransportHandlerTests extends AbstractHttpRequestTests public void handleRequestXhr() throws Exception { XhrPollingTransportHandler transportHandler = new XhrPollingTransportHandler(); - transportHandler.setSockJsConfiguration(this.sockJsConfig); + transportHandler.setSockJsServiceConfiguration(this.sockJsConfig); AbstractSockJsSession session = transportHandler.createSession("1", this.webSocketHandler); transportHandler.handleRequest(this.request, this.response, this.webSocketHandler, session); @@ -89,7 +97,7 @@ public class HttpSendingTransportHandlerTests extends AbstractHttpRequestTests public void jsonpTransport() throws Exception { JsonpPollingTransportHandler transportHandler = new JsonpPollingTransportHandler(); - transportHandler.setSockJsConfiguration(this.sockJsConfig); + transportHandler.setSockJsServiceConfiguration(this.sockJsConfig); PollingSockJsSession session = transportHandler.createSession("1", this.webSocketHandler); transportHandler.handleRequest(this.request, this.response, this.webSocketHandler, session); @@ -110,7 +118,7 @@ public class HttpSendingTransportHandlerTests extends AbstractHttpRequestTests public void handleRequestXhrStreaming() throws Exception { XhrStreamingTransportHandler transportHandler = new XhrStreamingTransportHandler(); - transportHandler.setSockJsConfiguration(this.sockJsConfig); + transportHandler.setSockJsServiceConfiguration(this.sockJsConfig); AbstractSockJsSession session = transportHandler.createSession("1", this.webSocketHandler); transportHandler.handleRequest(this.request, this.response, this.webSocketHandler, session); @@ -124,7 +132,7 @@ public class HttpSendingTransportHandlerTests extends AbstractHttpRequestTests public void htmlFileTransport() throws Exception { HtmlFileTransportHandler transportHandler = new HtmlFileTransportHandler(); - transportHandler.setSockJsConfiguration(this.sockJsConfig); + transportHandler.setSockJsServiceConfiguration(this.sockJsConfig); StreamingSockJsSession session = transportHandler.createSession("1", this.webSocketHandler); transportHandler.handleRequest(this.request, this.response, this.webSocketHandler, session); @@ -145,7 +153,7 @@ public class HttpSendingTransportHandlerTests extends AbstractHttpRequestTests public void eventSourceTransport() throws Exception { EventSourceTransportHandler transportHandler = new EventSourceTransportHandler(); - transportHandler.setSockJsConfiguration(this.sockJsConfig); + transportHandler.setSockJsServiceConfiguration(this.sockJsConfig); StreamingSockJsSession session = transportHandler.createSession("1", this.webSocketHandler); transportHandler.handleRequest(this.request, this.response, this.webSocketHandler, session); diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/AbstractHttpSockJsSessionTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSessionTests.java similarity index 88% rename from spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/AbstractHttpSockJsSessionTests.java rename to spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSessionTests.java index d9ccacedd1..39c3464929 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/AbstractHttpSockJsSessionTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSessionTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs.transport; +package org.springframework.web.socket.sockjs.transport.session; import java.io.IOException; @@ -28,12 +28,11 @@ import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.sockjs.BaseAbstractSockJsSessionTests; -import org.springframework.web.socket.sockjs.SockJsConfiguration; -import org.springframework.web.socket.sockjs.SockJsFrame; -import org.springframework.web.socket.sockjs.SockJsFrame.DefaultFrameFormat; -import org.springframework.web.socket.sockjs.SockJsFrame.FrameFormat; -import org.springframework.web.socket.sockjs.transport.AbstractHttpSockJsSessionTests.TestAbstractHttpSockJsSession; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.DefaultFrameFormat; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat; +import org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession; +import org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSessionTests.TestAbstractHttpSockJsSession; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -128,7 +127,7 @@ public class AbstractHttpSockJsSessionTests extends BaseAbstractSockJsSessionTes private boolean heartbeatScheduled; - public TestAbstractHttpSockJsSession(SockJsConfiguration config, WebSocketHandler handler) { + public TestAbstractHttpSockJsSession(SockJsServiceConfig config, WebSocketHandler handler) { super("1", config, handler); } diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/AbstractSockJsSessionTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSessionTests.java similarity index 95% rename from spring-websocket/src/test/java/org/springframework/web/socket/sockjs/AbstractSockJsSessionTests.java rename to spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSessionTests.java index b73d7d8b1d..987f859195 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/AbstractSockJsSessionTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSessionTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.web.socket.sockjs; +package org.springframework.web.socket.sockjs.transport.session; import java.io.IOException; import java.sql.Date; @@ -24,6 +24,9 @@ import java.util.concurrent.ScheduledFuture; import org.junit.Test; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.sockjs.SockJsProcessingException; +import org.springframework.web.socket.sockjs.support.frame.SockJsFrame; +import org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession; import static org.junit.Assert.*; import static org.mockito.Matchers.*; @@ -210,7 +213,7 @@ public class AbstractSockJsSessionTests extends BaseAbstractSockJsSessionTests heartbeatSchedulingEvents = new ArrayList<>(); - public TestWebSocketServerSockJsSession(SockJsConfiguration config, WebSocketHandler handler) { + public TestWebSocketServerSockJsSession(SockJsServiceConfig config, WebSocketHandler handler) { super("1", config, handler); }