diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java b/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java index 8c8a28406bd..3912dcb268b 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java @@ -26,7 +26,6 @@ import org.springframework.websocket.CloseStatus; import org.springframework.websocket.TextMessage; import org.springframework.websocket.WebSocketHandler; import org.springframework.websocket.WebSocketSession; -import org.springframework.websocket.adapter.WebSocketHandlerInvoker; /** @@ -42,7 +41,7 @@ public abstract class AbstractSockJsSession implements WebSocketSession { private final String sessionId; - private WebSocketHandlerInvoker handler; + private WebSocketHandler handler; private State state = State.NEW; @@ -59,7 +58,7 @@ public abstract class AbstractSockJsSession implements WebSocketSession { Assert.notNull(sessionId, "sessionId is required"); Assert.notNull(webSocketHandler, "webSocketHandler is required"); this.sessionId = sessionId; - this.handler = new WebSocketHandlerInvoker(webSocketHandler).setLogger(logger); + this.handler = webSocketHandler; } public String getId() { @@ -129,7 +128,13 @@ public abstract class AbstractSockJsSession implements WebSocketSession { */ protected void tryCloseWithSockJsTransportError(Throwable ex, CloseStatus closeStatus) { delegateError(ex); - this.handler.tryCloseWithError(this, ex, closeStatus); + try { + logger.error("Closing due to transport error for " + this, ex); + close(closeStatus); + } + catch (Throwable t) { + // ignore + } } public void delegateMessages(String[] messages) { diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/server/support/SockJsHttpRequestHandler.java b/spring-websocket/src/main/java/org/springframework/sockjs/server/support/SockJsHttpRequestHandler.java index 3c90f9db6dc..241e550a38f 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/server/support/SockJsHttpRequestHandler.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/server/support/SockJsHttpRequestHandler.java @@ -32,6 +32,8 @@ import org.springframework.web.HttpRequestHandler; import org.springframework.web.util.NestedServletException; import org.springframework.web.util.UrlPathHelper; import org.springframework.websocket.WebSocketHandler; +import org.springframework.websocket.support.ExceptionWebSocketHandlerDecorator; +import org.springframework.websocket.support.LoggingWebSocketHandlerDecorator; /** * @author Rossen Stoyanchev @@ -63,7 +65,18 @@ public class SockJsHttpRequestHandler implements HttpRequestHandler { this.prefix = prefix; this.sockJsService = sockJsService; - this.webSocketHandler = webSocketHandler; + this.webSocketHandler = decorateWebSocketHandler(webSocketHandler); + } + + /** + * Decorate the WebSocketHandler provided to the class constructor. + *
+ * By default {@link ExceptionWebSocketHandlerDecorator} and
+ * {@link LoggingWebSocketHandlerDecorator} are applied are added.
+ */
+ protected WebSocketHandler decorateWebSocketHandler(WebSocketHandler handler) {
+ handler = new ExceptionWebSocketHandlerDecorator(handler);
+ return new LoggingWebSocketHandlerDecorator(handler);
}
public String getPrefix() {
diff --git a/spring-websocket/src/main/java/org/springframework/websocket/WebSocketHandler.java b/spring-websocket/src/main/java/org/springframework/websocket/WebSocketHandler.java
index 1ea26cd3fe6..4220facf782 100644
--- a/spring-websocket/src/main/java/org/springframework/websocket/WebSocketHandler.java
+++ b/spring-websocket/src/main/java/org/springframework/websocket/WebSocketHandler.java
@@ -48,4 +48,9 @@ public interface WebSocketHandler {
*/
void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus);
+ /**
+ * Whether this WebSocketHandler wishes to receive messages broken up in parts.
+ */
+ boolean isStreaming();
+
}
diff --git a/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketListenerAdapter.java b/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketListenerAdapter.java
index d8aa4f2d137..163ffa057fd 100644
--- a/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketListenerAdapter.java
+++ b/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketListenerAdapter.java
@@ -16,8 +16,6 @@
package org.springframework.websocket.adapter;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketListener;
import org.springframework.util.Assert;
@@ -35,8 +33,6 @@ import org.springframework.websocket.WebSocketSession;
*/
public class JettyWebSocketListenerAdapter implements WebSocketListener {
- private static Log logger = LogFactory.getLog(JettyWebSocketListenerAdapter.class);
-
private final WebSocketHandler webSocketHandler;
private WebSocketSession wsSession;
@@ -44,7 +40,7 @@ public class JettyWebSocketListenerAdapter implements WebSocketListener {
public JettyWebSocketListenerAdapter(WebSocketHandler webSocketHandler) {
Assert.notNull(webSocketHandler, "webSocketHandler is required");
- this.webSocketHandler = new WebSocketHandlerInvoker(webSocketHandler).setLogger(logger);
+ this.webSocketHandler = webSocketHandler;
}
@@ -76,4 +72,5 @@ public class JettyWebSocketListenerAdapter implements WebSocketListener {
public void onWebSocketError(Throwable cause) {
this.webSocketHandler.handleTransportError(this.wsSession, cause);
}
+
}
diff --git a/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardEndpointAdapter.java b/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardEndpointAdapter.java
index c076eebe423..a36249078e9 100644
--- a/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardEndpointAdapter.java
+++ b/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardEndpointAdapter.java
@@ -23,12 +23,9 @@ import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.websocket.BinaryMessage;
import org.springframework.websocket.CloseStatus;
-import org.springframework.websocket.PartialMessageHandler;
import org.springframework.websocket.TextMessage;
import org.springframework.websocket.WebSocketHandler;
import org.springframework.websocket.WebSocketSession;
@@ -42,26 +39,23 @@ import org.springframework.websocket.WebSocketSession;
*/
public class StandardEndpointAdapter extends Endpoint {
- private static Log logger = LogFactory.getLog(StandardEndpointAdapter.class);
-
- private final WebSocketHandlerInvoker handler;
-
- private final Class> handlerClass;
+ private final WebSocketHandler handler;
private WebSocketSession wsSession;
-
public StandardEndpointAdapter(WebSocketHandler webSocketHandler) {
Assert.notNull(webSocketHandler, "webSocketHandler is required");
- this.handler = new WebSocketHandlerInvoker(webSocketHandler).setLogger(logger);
- this.handlerClass= webSocketHandler.getClass();
+ this.handler = webSocketHandler;
}
@Override
public void onOpen(final javax.websocket.Session session, EndpointConfig config) {
+ this.wsSession = new StandardWebSocketSessionAdapter(session);
+ this.handler.afterConnectionEstablished(this.wsSession);
+
session.addMessageHandler(new MessageHandler.Whole
+ * By default {@link ExceptionWebSocketHandlerDecorator} and
+ * {@link LoggingWebSocketHandlerDecorator} are applied are added.
+ */
+ protected WebSocketHandler decorateWebSocketHandler(WebSocketHandler handler) {
+ handler = new ExceptionWebSocketHandlerDecorator(handler);
+ return new LoggingWebSocketHandlerDecorator(handler);
}
public void setSubProtocols(List
+ * By default {@link ExceptionWebSocketHandlerDecorator} and
+ * {@link LoggingWebSocketHandlerDecorator} are applied are added.
+ */
+ protected WebSocketHandler decorateWebSocketHandler(WebSocketHandler handler) {
+ handler = new ExceptionWebSocketHandlerDecorator(handler);
+ return new LoggingWebSocketHandlerDecorator(handler);
+ }
+
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
diff --git a/spring-websocket/src/main/java/org/springframework/websocket/support/ExceptionWebSocketHandlerDecorator.java b/spring-websocket/src/main/java/org/springframework/websocket/support/ExceptionWebSocketHandlerDecorator.java
new file mode 100644
index 00000000000..8d45636d198
--- /dev/null
+++ b/spring-websocket/src/main/java/org/springframework/websocket/support/ExceptionWebSocketHandlerDecorator.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2002-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.websocket.support;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.websocket.CloseStatus;
+import org.springframework.websocket.WebSocketHandler;
+import org.springframework.websocket.WebSocketMessage;
+import org.springframework.websocket.WebSocketSession;
+
+
+/**
+ * @author Rossen Stoyanchev
+ * @since 4.0
+ */
+public class ExceptionWebSocketHandlerDecorator extends WebSocketHandlerDecorator {
+
+ private Log logger = LogFactory.getLog(ExceptionWebSocketHandlerDecorator.class);
+
+
+ public ExceptionWebSocketHandlerDecorator(WebSocketHandler delegate) {
+ super(delegate);
+ }
+
+ @Override
+ public void afterConnectionEstablished(WebSocketSession session) {
+ try {
+ getDelegate().afterConnectionEstablished(session);
+ }
+ catch (Throwable ex) {
+ tryCloseWithError(session, ex);
+ }
+ }
+
+ private void tryCloseWithError(WebSocketSession session, Throwable exception) {
+ logger.error("Closing due to exception for " + session, exception);
+ if (session.isOpen()) {
+ try {
+ session.close(CloseStatus.SERVER_ERROR);
+ }
+ catch (Throwable t) {
+ // ignore
+ }
+ }
+ }
+
+ @Override
+ public void handleMessage(WebSocketSession session, WebSocketMessage> message) {
+ try {
+ getDelegate().handleMessage(session, message);
+ }
+ catch (Throwable ex) {
+ tryCloseWithError(session,ex);
+ }
+ }
+
+ @Override
+ public void handleTransportError(WebSocketSession session, Throwable exception) {
+ try {
+ getDelegate().handleTransportError(session, exception);
+ }
+ catch (Throwable ex) {
+ tryCloseWithError(session, ex);
+ }
+ }
+
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
+ try {
+ getDelegate().afterConnectionClosed(session, closeStatus);
+ }
+ catch (Throwable ex) {
+ logger.error("Unhandled error for " + this, ex);
+ }
+ }
+
+}
diff --git a/spring-websocket/src/main/java/org/springframework/websocket/support/LoggingWebSocketHandlerDecorator.java b/spring-websocket/src/main/java/org/springframework/websocket/support/LoggingWebSocketHandlerDecorator.java
new file mode 100644
index 00000000000..8cb0e0e8c21
--- /dev/null
+++ b/spring-websocket/src/main/java/org/springframework/websocket/support/LoggingWebSocketHandlerDecorator.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2002-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.websocket.support;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.websocket.CloseStatus;
+import org.springframework.websocket.WebSocketHandler;
+import org.springframework.websocket.WebSocketMessage;
+import org.springframework.websocket.WebSocketSession;
+
+
+/**
+ * @author Rossen Stoyanchev
+ * @since 4.0
+ */
+public class LoggingWebSocketHandlerDecorator extends WebSocketHandlerDecorator {
+
+ private Log logger = LogFactory.getLog(LoggingWebSocketHandlerDecorator.class);
+
+
+ public LoggingWebSocketHandlerDecorator(WebSocketHandler delegate) {
+ super(delegate);
+ }
+
+
+ @Override
+ public void afterConnectionEstablished(WebSocketSession session) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Connection established, " + session + ", uri=" + session.getURI());
+ }
+ super.afterConnectionEstablished(session);
+ }
+
+ @Override
+ public void handleMessage(WebSocketSession session, WebSocketMessage> message) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("Received " + message + ", " + session);
+ }
+ super.handleMessage(session, message);
+ }
+
+ @Override
+ public void handleTransportError(WebSocketSession session, Throwable exception) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Transport error for " + session, exception);
+ }
+ super.handleTransportError(session, exception);
+ }
+
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Connection closed for " + session + ", " + closeStatus);
+ }
+ super.afterConnectionClosed(session, closeStatus);
+ }
+
+}
diff --git a/spring-websocket/src/main/java/org/springframework/websocket/support/PerConnectionWebSocketHandlerProxy.java b/spring-websocket/src/main/java/org/springframework/websocket/support/PerConnectionWebSocketHandlerProxy.java
index ee4091178f4..7d39bd0caf7 100644
--- a/spring-websocket/src/main/java/org/springframework/websocket/support/PerConnectionWebSocketHandlerProxy.java
+++ b/spring-websocket/src/main/java/org/springframework/websocket/support/PerConnectionWebSocketHandlerProxy.java
@@ -57,11 +57,23 @@ public class PerConnectionWebSocketHandlerProxy implements WebSocketHandler, Bea
private Map