Skip to content

Commit 2794224

Browse files
committed
Add onClosed to SockJsSessionSupport sub-classes
As opposed to close(), which actively closes the session, the onClosed method is called when the underlying connection has been closed or disconnected.
1 parent f056f7e commit 2794224

14 files changed

+253
-182
lines changed

spring-websocket/src/main/java/org/springframework/sockjs/SockJsSession.java

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
*/
2828
public interface SockJsSession {
2929

30+
String getId();
31+
3032
void sendMessage(String text) throws IOException;
3133

3234
void close();

spring-websocket/src/main/java/org/springframework/sockjs/SockJsSessionSupport.java

+5
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ public void delegateException(Throwable ex) {
114114
this.sockJsHandler.handleException(this, ex);
115115
}
116116

117+
public void connectionClosed() {
118+
this.state = State.CLOSED;
119+
this.sockJsHandler.sessionClosed(this);
120+
}
121+
117122
public void close() {
118123
this.state = State.CLOSED;
119124
this.sockJsHandler.sessionClosed(this);

spring-websocket/src/main/java/org/springframework/sockjs/server/AbstractServerSession.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,18 @@ public final synchronized void sendMessage(String message) throws IOException {
5858

5959
protected abstract void sendMessageInternal(String message) throws IOException;
6060

61+
62+
@Override
63+
public void connectionClosed() {
64+
logger.debug("Session closed");
65+
super.close();
66+
cancelHeartbeat();
67+
}
68+
69+
@Override
6170
public final synchronized void close() {
6271
if (!isClosed()) {
6372
logger.debug("Closing session");
64-
6573
if (isActive()) {
6674
// deliver messages "in flight" before sending close frame
6775
try {
@@ -71,9 +79,7 @@ public final synchronized void close() {
7179
// ignore
7280
}
7381
}
74-
7582
super.close();
76-
7783
cancelHeartbeat();
7884
closeInternal();
7985
}

spring-websocket/src/main/java/org/springframework/sockjs/server/AbstractSockJsService.java

+11-22
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import org.springframework.util.DigestUtils;
4141
import org.springframework.util.ObjectUtils;
4242
import org.springframework.util.StringUtils;
43-
import org.springframework.web.util.UriUtils;
4443

4544

4645
/**
@@ -57,7 +56,7 @@ public abstract class AbstractSockJsService
5756
private static final int ONE_YEAR = 365 * 24 * 60 * 60;
5857

5958

60-
private final String prefix;
59+
private String name = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
6160

6261
private String clientLibraryUrl = "https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js";
6362

@@ -74,31 +73,25 @@ public abstract class AbstractSockJsService
7473
private final TaskSchedulerHolder heartbeatSchedulerHolder;
7574

7675

77-
/**
78-
* Class constructor...
79-
*
80-
* @param prefix the path prefix for the SockJS service. All requests with a path
81-
* that begins with the specified prefix will be handled by this service. In a
82-
* Servlet container this is the path within the current servlet mapping.
83-
*/
84-
public AbstractSockJsService(String prefix) {
85-
Assert.hasText(prefix, "prefix is required");
86-
this.prefix = prefix;
76+
77+
public AbstractSockJsService() {
8778
this.heartbeatSchedulerHolder = new TaskSchedulerHolder("SockJs-heartbeat-");
8879
}
8980

90-
public AbstractSockJsService(String prefix, TaskScheduler heartbeatScheduler) {
91-
Assert.hasText(prefix, "prefix is required");
81+
public AbstractSockJsService(TaskScheduler heartbeatScheduler) {
9282
Assert.notNull(heartbeatScheduler, "heartbeatScheduler is required");
93-
this.prefix = prefix;
9483
this.heartbeatSchedulerHolder = new TaskSchedulerHolder(heartbeatScheduler);
9584
}
9685

9786
/**
98-
* The path prefix to which the SockJS service is mapped.
87+
* A unique name for the service mainly for logging purposes.
9988
*/
100-
public String getPrefix() {
101-
return this.prefix;
89+
public void setName(String name) {
90+
this.name = name;
91+
}
92+
93+
public String getName() {
94+
return this.name;
10295
}
10396

10497
/**
@@ -236,10 +229,6 @@ public final void handleRequest(ServerHttpRequest request, ServerHttpResponse re
236229
// Ignore invalid Content-Type (TODO)
237230
}
238231

239-
String path = UriUtils.decode(request.getURI().getPath(), "URF-8");
240-
int index = path.indexOf(this.prefix);
241-
sockJsPath = path.substring(index + this.prefix.length());
242-
243232
try {
244233
if (sockJsPath.equals("") || sockJsPath.equals("/")) {
245234
response.getHeaders().setContentType(new MediaType("text", "plain", Charset.forName("UTF-8")));

spring-websocket/src/main/java/org/springframework/sockjs/server/SockJsService.java

-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
*/
3232
public interface SockJsService {
3333

34-
String getPrefix();
35-
3634
/**
3735
* Pre-register {@link SockJsHandler} instances so they can be adapted to
3836
* {@link WebSocketHandler} and hence re-used at runtime when

spring-websocket/src/main/java/org/springframework/sockjs/server/support/DefaultSockJsService.java

+6-8
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,11 @@ public class DefaultSockJsService extends AbstractSockJsService implements Initi
7070
private final Map<SockJsHandler, WebSocketHandler> sockJsHandlers = new HashMap<SockJsHandler, WebSocketHandler>();
7171

7272

73-
public DefaultSockJsService(String prefix) {
74-
super(prefix);
73+
public DefaultSockJsService() {
7574
this.sessionTimeoutSchedulerHolder = new TaskSchedulerHolder("SockJs-sessionTimeout-");
7675
}
7776

78-
public DefaultSockJsService(String prefix, TaskScheduler heartbeatScheduler, TaskScheduler sessionTimeoutScheduler) {
79-
super(prefix, heartbeatScheduler);
77+
public DefaultSockJsService(TaskScheduler heartbeatScheduler, TaskScheduler sessionTimeoutScheduler) {
8078
Assert.notNull(sessionTimeoutScheduler, "sessionTimeoutScheduler is required");
8179
this.sessionTimeoutSchedulerHolder = new TaskSchedulerHolder(sessionTimeoutScheduler);
8280
}
@@ -146,23 +144,23 @@ public void run() {
146144
try {
147145
int count = sessions.size();
148146
if (logger.isTraceEnabled() && (count != 0)) {
149-
logger.trace("Checking " + count + " session(s) for timeouts [" + getPrefix() + "]");
147+
logger.trace("Checking " + count + " session(s) for timeouts [" + getName() + "]");
150148
}
151149
for (SockJsSessionSupport session : sessions.values()) {
152150
if (session.getTimeSinceLastActive() > getDisconnectDelay()) {
153151
if (logger.isTraceEnabled()) {
154-
logger.trace("Removing " + session + " for [" + getPrefix() + "]");
152+
logger.trace("Removing " + session + " for [" + getName() + "]");
155153
}
156154
session.close();
157155
sessions.remove(session.getId());
158156
}
159157
}
160158
if (logger.isTraceEnabled() && (count != 0)) {
161-
logger.trace(sessions.size() + " remaining session(s) [" + getPrefix() + "]");
159+
logger.trace(sessions.size() + " remaining session(s) [" + getName() + "]");
162160
}
163161
}
164162
catch (Throwable t) {
165-
logger.error("Failed to complete session timeout checks for [" + getPrefix() + "]", t);
163+
logger.error("Failed to complete session timeout checks for [" + getName() + "]", t);
166164
}
167165
}
168166
}, getDisconnectDelay());

spring-websocket/src/main/java/org/springframework/sockjs/server/support/SockJsHttpRequestHandler.java

+35-7
Original file line numberDiff line numberDiff line change
@@ -46,30 +46,59 @@
4646
*/
4747
public class SockJsHttpRequestHandler implements HttpRequestHandler, BeanFactoryAware {
4848

49+
private final String prefix;
50+
4951
private final SockJsService sockJsService;
5052

5153
private final HandlerProvider<SockJsHandler> handlerProvider;
5254

5355
private final UrlPathHelper urlPathHelper = new UrlPathHelper();
5456

5557

56-
public SockJsHttpRequestHandler(SockJsService sockJsService, SockJsHandler sockJsHandler) {
58+
/**
59+
* Class constructor with {@link SockJsHandler} instance ...
60+
*
61+
* @param prefix the path prefix for the SockJS service. All requests with a path
62+
* that begins with the specified prefix will be handled by this service. In a
63+
* Servlet container this is the path within the current servlet mapping.
64+
*/
65+
public SockJsHttpRequestHandler(String prefix, SockJsService sockJsService, SockJsHandler sockJsHandler) {
66+
67+
Assert.hasText(prefix, "prefix is required");
5768
Assert.notNull(sockJsService, "sockJsService is required");
5869
Assert.notNull(sockJsHandler, "sockJsHandler is required");
70+
71+
this.prefix = prefix;
5972
this.sockJsService = sockJsService;
6073
this.sockJsService.registerSockJsHandlers(Collections.singleton(sockJsHandler));
6174
this.handlerProvider = new HandlerProvider<SockJsHandler>(sockJsHandler);
6275
}
6376

64-
public SockJsHttpRequestHandler(SockJsService sockJsService, Class<? extends SockJsHandler> sockJsHandlerClass) {
77+
/**
78+
* Class constructor with {@link SockJsHandler} type (per request) ...
79+
*
80+
* @param prefix the path prefix for the SockJS service. All requests with a path
81+
* that begins with the specified prefix will be handled by this service. In a
82+
* Servlet container this is the path within the current servlet mapping.
83+
*/
84+
public SockJsHttpRequestHandler(String prefix, SockJsService sockJsService,
85+
Class<? extends SockJsHandler> sockJsHandlerClass) {
86+
87+
Assert.hasText(prefix, "prefix is required");
6588
Assert.notNull(sockJsService, "sockJsService is required");
6689
Assert.notNull(sockJsHandlerClass, "sockJsHandlerClass is required");
90+
91+
this.prefix = prefix;
6792
this.sockJsService = sockJsService;
6893
this.handlerProvider = new HandlerProvider<SockJsHandler>(sockJsHandlerClass);
6994
}
7095

71-
public String getMappingPattern() {
72-
return this.sockJsService.getPrefix() + "/**";
96+
public String getPrefix() {
97+
return this.prefix;
98+
}
99+
100+
public String getPattern() {
101+
return this.prefix + "/**";
73102
}
74103

75104
@Override
@@ -82,10 +111,9 @@ public void handleRequest(HttpServletRequest request, HttpServletResponse respon
82111
throws ServletException, IOException {
83112

84113
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
85-
String prefix = this.sockJsService.getPrefix();
86114

87-
Assert.isTrue(lookupPath.startsWith(prefix),
88-
"Request path does not match the prefix of the SockJsService " + prefix);
115+
Assert.isTrue(lookupPath.startsWith(this.prefix),
116+
"Request path does not match the prefix of the SockJsService " + this.prefix);
89117

90118
String sockJsPath = lookupPath.substring(prefix.length());
91119

spring-websocket/src/main/java/org/springframework/sockjs/server/transport/AbstractHttpServerSession.java

+7
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ private void tryFlushCache() throws IOException {
108108
*/
109109
protected abstract void flushCache() throws IOException;
110110

111+
@Override
112+
public void connectionClosed() {
113+
super.connectionClosed();
114+
resetRequest();
115+
}
116+
117+
@Override
111118
protected void closeInternal() {
112119
resetRequest();
113120
}

spring-websocket/src/main/java/org/springframework/sockjs/server/transport/AbstractSockJsWebSocketHandler.java

-108
This file was deleted.

0 commit comments

Comments
 (0)