Skip to content

Commit 5809f5b

Browse files
committed
SubProtocolWebSocketHandler provides protected decorateSession method
Issue: SPR-16089
1 parent d418ba1 commit 5809f5b

File tree

3 files changed

+48
-34
lines changed

3 files changed

+48
-34
lines changed

spring-websocket/src/main/java/org/springframework/web/socket/handler/ConcurrentWebSocketSessionDecorator.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public void sendMessage(WebSocketMessage<?> message) throws IOException {
126126
if (logger.isTraceEnabled()) {
127127
String text = String.format("Another send already in progress: " +
128128
"session id '%s':, \"in-progress\" send time %d (ms), buffer size %d bytes",
129-
getId(), getTimeSinceSendStarted(), this.bufferSize.get());
129+
getId(), getTimeSinceSendStarted(), getBufferSize());
130130
logger.trace(text);
131131
}
132132
checkSessionLimits();
@@ -166,14 +166,14 @@ private boolean tryFlushMessageBuffer() throws IOException {
166166
private void checkSessionLimits() {
167167
if (!shouldNotSend() && this.closeLock.tryLock()) {
168168
try {
169-
if (getTimeSinceSendStarted() > this.sendTimeLimit) {
169+
if (getTimeSinceSendStarted() > getSendTimeLimit()) {
170170
String format = "Message send time %d (ms) for session '%s' exceeded the allowed limit %d";
171-
String reason = String.format(format, getTimeSinceSendStarted(), getId(), this.sendTimeLimit);
171+
String reason = String.format(format, getTimeSinceSendStarted(), getId(), getSendTimeLimit());
172172
limitExceeded(reason);
173173
}
174-
else if (this.bufferSize.get() > this.bufferSizeLimit) {
174+
else if (getBufferSize() > getBufferSizeLimit()) {
175175
String format = "The send buffer size %d bytes for session '%s' exceeded the allowed limit %d";
176-
String reason = String.format(format, this.bufferSize.get(), getId(), this.bufferSizeLimit);
176+
String reason = String.format(format, getBufferSize(), getId(), getBufferSizeLimit());
177177
limitExceeded(reason);
178178
}
179179
}

spring-websocket/src/main/java/org/springframework/web/socket/messaging/SubProtocolHandler.java

+14-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,24 +26,23 @@
2626
import org.springframework.web.socket.WebSocketSession;
2727

2828
/**
29-
* A contract for handling WebSocket messages as part of a higher level protocol, referred
30-
* to as "sub-protocol" in the WebSocket RFC specification. Handles both
29+
* A contract for handling WebSocket messages as part of a higher level protocol,
30+
* referred to as "sub-protocol" in the WebSocket RFC specification. Handles both
3131
* {@link WebSocketMessage}s from a client as well as {@link Message}s to a client.
32-
* <p>
33-
* Implementations of this interface can be configured on a
34-
* {@link SubProtocolWebSocketHandler} which selects a sub-protocol handler to delegate
35-
* messages to based on the sub-protocol requested by the client through the
36-
* {@code Sec-WebSocket-Protocol} request header.
32+
*
33+
* <p>Implementations of this interface can be configured on a
34+
* {@link SubProtocolWebSocketHandler} which selects a sub-protocol handler to
35+
* delegate messages to based on the sub-protocol requested by the client through
36+
* the {@code Sec-WebSocket-Protocol} request header.
3737
*
3838
* @author Andy Wilkinson
3939
* @author Rossen Stoyanchev
40-
*
4140
* @since 4.0
4241
*/
4342
public interface SubProtocolHandler {
4443

4544
/**
46-
* Return the list of sub-protocols supported by this handler, never {@code null}.
45+
* Return the list of sub-protocols supported by this handler (never {@code null}).
4746
*/
4847
List<String> getSupportedProtocols();
4948

@@ -53,12 +52,11 @@ public interface SubProtocolHandler {
5352
* @param message the client message
5453
* @param outputChannel an output channel to send messages to
5554
*/
56-
void handleMessageFromClient(WebSocketSession session, WebSocketMessage<?> message,
57-
MessageChannel outputChannel) throws Exception;
55+
void handleMessageFromClient(WebSocketSession session, WebSocketMessage<?> message, MessageChannel outputChannel)
56+
throws Exception;
5857

5958
/**
60-
* Handle the given {@link Message} to the client associated with the given WebSocket
61-
* session.
59+
* Handle the given {@link Message} to the client associated with the given WebSocket session.
6260
* @param session the client session
6361
* @param message the client message
6462
*/
@@ -84,7 +82,7 @@ void handleMessageFromClient(WebSocketSession session, WebSocketMessage<?> messa
8482
* @param closeStatus the reason why the session was closed
8583
* @param outputChannel a channel
8684
*/
87-
void afterSessionEnded(WebSocketSession session, CloseStatus closeStatus,
88-
MessageChannel outputChannel) throws Exception;
85+
void afterSessionEnded(WebSocketSession session, CloseStatus closeStatus, MessageChannel outputChannel)
86+
throws Exception;
8987

9088
}

spring-websocket/src/main/java/org/springframework/web/socket/messaging/SubProtocolWebSocketHandler.java

+29-13
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.web.socket.messaging;
1818

19-
import java.io.IOException;
2019
import java.util.ArrayList;
2120
import java.util.Collections;
2221
import java.util.LinkedHashSet;
@@ -292,7 +291,7 @@ public void afterConnectionEstablished(WebSocketSession session) throws Exceptio
292291
return;
293292
}
294293
this.stats.incrementSessionCount(session);
295-
session = new ConcurrentWebSocketSessionDecorator(session, getSendTimeLimit(), getSendBufferSizeLimit());
294+
session = decorateSession(session);
296295
this.sessions.put(session.getId(), new WebSocketSessionHolder(session));
297296
findProtocolHandler(session).afterSessionStarted(session, this.clientInboundChannel);
298297
}
@@ -377,6 +376,23 @@ public boolean supportsPartialMessages() {
377376
}
378377

379378

379+
/**
380+
* Decorate the given {@link WebSocketSession}, if desired.
381+
* <p>The default implementation builds a {@link ConcurrentWebSocketSessionDecorator}
382+
* with the configured {@link #getSendTimeLimit() send-time limit} and
383+
* {@link #getSendBufferSizeLimit() buffer-size limit}.
384+
* @param session the original {@code WebSocketSession}
385+
* @return the decorated {@code WebSocketSession}, or potentially the given session as-is
386+
* @since 4.3.13
387+
*/
388+
protected WebSocketSession decorateSession(WebSocketSession session) {
389+
return new ConcurrentWebSocketSessionDecorator(session, getSendTimeLimit(), getSendBufferSizeLimit());
390+
}
391+
392+
/**
393+
* Find a {@link SubProtocolHandler} for the given session.
394+
* @param session the {@code WebSocketSession} to find a handler for
395+
*/
380396
protected final SubProtocolHandler findProtocolHandler(WebSocketSession session) {
381397
String protocol = null;
382398
try {
@@ -432,12 +448,11 @@ private String resolveSessionId(Message<?> message) {
432448
* When a session is connected through a higher-level protocol it has a chance
433449
* to use heartbeat management to shut down sessions that are too slow to send
434450
* or receive messages. However, after a WebSocketSession is established and
435-
* before the higher level protocol is fully connected there is a possibility
436-
* for sessions to hang. This method checks and closes any sessions that have
437-
* been connected for more than 60 seconds without having received a single
438-
* message.
451+
* before the higher level protocol is fully connected there is a possibility for
452+
* sessions to hang. This method checks and closes any sessions that have been
453+
* connected for more than 60 seconds without having received a single message.
439454
*/
440-
private void checkSessions() throws IOException {
455+
private void checkSessions() {
441456
long currentTime = System.currentTimeMillis();
442457
if (!isRunning() || (currentTime - this.lastSessionCheckTime < TIME_TO_FIRST_MESSAGE)) {
443458
return;
@@ -497,12 +512,13 @@ private static class WebSocketSessionHolder {
497512

498513
private final WebSocketSession session;
499514

500-
private final long createTime = System.currentTimeMillis();
515+
private final long createTime;
501516

502-
private volatile boolean handledMessages;
517+
private volatile boolean hasHandledMessages;
503518

504-
private WebSocketSessionHolder(WebSocketSession session) {
519+
public WebSocketSessionHolder(WebSocketSession session) {
505520
this.session = session;
521+
this.createTime = System.currentTimeMillis();
506522
}
507523

508524
public WebSocketSession getSession() {
@@ -514,17 +530,17 @@ public long getCreateTime() {
514530
}
515531

516532
public void setHasHandledMessages() {
517-
this.handledMessages = true;
533+
this.hasHandledMessages = true;
518534
}
519535

520536
public boolean hasHandledMessages() {
521-
return this.handledMessages;
537+
return this.hasHandledMessages;
522538
}
523539

524540
@Override
525541
public String toString() {
526542
return "WebSocketSessionHolder[session=" + this.session + ", createTime=" +
527-
this.createTime + ", hasHandledMessages=" + this.handledMessages + "]";
543+
this.createTime + ", hasHandledMessages=" + this.hasHandledMessages + "]";
528544
}
529545
}
530546

0 commit comments

Comments
 (0)