From 7e7b2e2950a8edc304b9ee9a3b555f0f2c56f320 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Wed, 6 May 2015 10:15:48 -0700 Subject: [PATCH] 420678 - Add WebSocketPartialListener to support receiving partial WebSocket TEXT/BINARY messages + Reworking WebSocketListener to be based on new WebSocketConnectionListener + Adding new WebSocketPartialListener and example --- .../api/WebSocketConnectionListener.java | 61 +++++++++++++++++++ .../websocket/api/WebSocketListener.java | 40 +----------- .../api/WebSocketPartialListener.java | 58 ++++++++++++++++++ .../java/examples/ListenerPartialSocket.java | 60 ++++++++++++++++++ 4 files changed, 181 insertions(+), 38 deletions(-) create mode 100644 jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConnectionListener.java create mode 100644 jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPartialListener.java create mode 100644 jetty-websocket/websocket-common/src/test/java/examples/ListenerPartialSocket.java diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConnectionListener.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConnectionListener.java new file mode 100644 index 00000000000..dc75fe6e910 --- /dev/null +++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConnectionListener.java @@ -0,0 +1,61 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.api; + +/** + * Core WebSocket Connection Listener + */ +public interface WebSocketConnectionListener +{ + /** + * A Close Event was received. + *

+ * The underlying Connection will be considered closed at this point. + * + * @param statusCode + * the close status code. (See {@link StatusCode}) + * @param reason + * the optional reason for the close. + */ + void onWebSocketClose(int statusCode, String reason); + + /** + * A WebSocket {@link Session} has connected successfully and is ready to be used. + *

+ * Note: It is a good idea to track this session as a field in your object so that you can write messages back via the {@link RemoteEndpoint} + * + * @param session + * the websocket session. + */ + void onWebSocketConnect(Session session); + + /** + * A WebSocket exception has occurred. + *

+ * This is a way for the internal implementation to notify of exceptions occured during the processing of websocket. + *

+ * Usually this occurs from bad / malformed incoming packets. (example: bad UTF8 data, frames that are too big, violations of the spec) + *

+ * This will result in the {@link Session} being closed by the implementing side. + * + * @param cause + * the error that occurred. + */ + void onWebSocketError(Throwable cause); +} diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketListener.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketListener.java index 0037b325478..9bb12c4458d 100644 --- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketListener.java +++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketListener.java @@ -19,9 +19,9 @@ package org.eclipse.jetty.websocket.api; /** - * Basic WebSocket Listener interface for incoming WebSocket events. + * Basic WebSocket Listener interface for incoming WebSocket message events. */ -public interface WebSocketListener +public interface WebSocketListener extends WebSocketConnectionListener { /** * A WebSocket binary frame has been received. @@ -35,42 +35,6 @@ public interface WebSocketListener */ void onWebSocketBinary(byte payload[], int offset, int len); - /** - * A Close Event was received. - *

- * The underlying Connection will be considered closed at this point. - * - * @param statusCode - * the close status code. (See {@link StatusCode}) - * @param reason - * the optional reason for the close. - */ - void onWebSocketClose(int statusCode, String reason); - - /** - * A WebSocket {@link Session} has connected successfully and is ready to be used. - *

- * Note: It is a good idea to track this session as a field in your object so that you can write messages back via the {@link RemoteEndpoint} - * - * @param session - * the websocket session. - */ - void onWebSocketConnect(Session session); - - /** - * A WebSocket exception has occurred. - *

- * This is a way for the internal implementation to notify of exceptions occured during the processing of websocket. - *

- * Usually this occurs from bad / malformed incoming packets. (example: bad UTF8 data, frames that are too big, violations of the spec) - *

- * This will result in the {@link Session} being closed by the implementing side. - * - * @param cause - * the error that occurred. - */ - void onWebSocketError(Throwable cause); - /** * A WebSocket Text frame was received. * diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPartialListener.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPartialListener.java new file mode 100644 index 00000000000..a9d03cdb5c1 --- /dev/null +++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPartialListener.java @@ -0,0 +1,58 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.api; + +import java.nio.ByteBuffer; + +/** + * WebSocket Partial Message Listener interface for incoming WebSocket TEXT/BINARY/CONTINUATION frames. + */ +public interface WebSocketPartialListener extends WebSocketConnectionListener +{ + /** + * A WebSocket BINARY (or associated CONTINUATION) frame has been received. + *

+ * Important Note: The payload ByteBuffer cannot be modified, and the ByteBuffer object itself + * will be recycled on completion of this method call, make a copy of the data contained within if you want to + * retain it between calls. + * + * @param payload + * the binary message frame payload + * @param fin + * true if this is the final frame, false otherwise + */ + void onWebSocketPartialBinary(ByteBuffer payload, boolean fin); + + /** + * A WebSocket TEXT (or associated CONTINUATION) frame has been received. + * + * @param payload + * the text message payload + *

+ * Note that due to framing, there is a above average chance of any UTF8 sequences being split on the + * border between two frames will result in either the previous frame, or the next frame having an + * invalid UTF8 sequence, but the combined frames having a valid UTF8 sequence. + *

+ * The String being provided here will not end in a split UTF8 sequence. Instead this partial sequence + * will be held over until the next frame is received. + * @param fin + * true if this is the final frame, false otherwise + */ + void onWebSocketPartialText(String payload, boolean fin); +} diff --git a/jetty-websocket/websocket-common/src/test/java/examples/ListenerPartialSocket.java b/jetty-websocket/websocket-common/src/test/java/examples/ListenerPartialSocket.java new file mode 100644 index 00000000000..d48cca8c8bc --- /dev/null +++ b/jetty-websocket/websocket-common/src/test/java/examples/ListenerPartialSocket.java @@ -0,0 +1,60 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package examples; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.WebSocketPartialListener; +import org.eclipse.jetty.websocket.common.events.EventCapture; + +public class ListenerPartialSocket implements WebSocketPartialListener +{ + public EventCapture capture = new EventCapture(); + + @Override + public void onWebSocketClose(int statusCode, String reason) + { + capture.add("onWebSocketClose(%d, %s)",statusCode,capture.q(reason)); + } + + @Override + public void onWebSocketConnect(Session session) + { + capture.add("onWebSocketConnect(%s)",session); + } + + @Override + public void onWebSocketError(Throwable cause) + { + capture.add("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage()); + } + + @Override + public void onWebSocketPartialText(String payload, boolean fin) + { + capture.add("onWebSocketPartialText('%s', %b)",payload,fin); + } + + @Override + public void onWebSocketPartialBinary(ByteBuffer payload, boolean fin) + { + capture.add("onWebSocketPartialBinary(%s [%d], %b)",payload,payload.remaining(),fin); + } +}