Improve ConcurrentWebSocketSessionDecorator

Before this change the decorator ensured that for a specific WebSocket
session only one thread at a time can send a message. Other threads
attempting to send would have their messages buffered and each time
that occurs, a check is also made to see if the buffer limit has been
reached or the send time limit has been exceeded and if so the session
is closed.

This change adds further protection to ensure only one thread at a time
can perform the session limit checks and attempt to close the session.
Furthermore if the session has timed out and become unresponsive,
attempts to close it may block yet another thread. Taking this into
consideration this change also ensures that state associated with the
session is cleaned first before an attempt is made to close the session.

Issue: SPR-11450
This commit is contained in:
Rossen Stoyanchev
2014-03-22 17:06:45 -04:00
parent 299be08268
commit ffac748f1c
5 changed files with 163 additions and 41 deletions

View File

@@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Unit tests for
@@ -55,7 +56,7 @@ public class ConcurrentWebSocketSessionDecoratorTests {
assertEquals(textMessage, session.getSentMessages().get(0));
assertEquals(0, concurrentSession.getBufferSize());
assertEquals(0, concurrentSession.getInProgressSendTime());
assertEquals(0, concurrentSession.getTimeSinceSendStarted());
assertTrue(session.isOpen());
}
@@ -86,14 +87,14 @@ public class ConcurrentWebSocketSessionDecoratorTests {
// ensure some send time elapses
Thread.sleep(100);
assertTrue(concurrentSession.getInProgressSendTime() > 0);
assertTrue(concurrentSession.getTimeSinceSendStarted() > 0);
TextMessage payload = new TextMessage("payload");
for (int i=0; i < 5; i++) {
concurrentSession.sendMessage(payload);
}
assertTrue(concurrentSession.getInProgressSendTime() > 0);
assertTrue(concurrentSession.getTimeSinceSendStarted() > 0);
assertEquals(5 * payload.getPayloadLength(), concurrentSession.getBufferSize());
assertTrue(blockingSession.isOpen());
}
@@ -129,10 +130,13 @@ public class ConcurrentWebSocketSessionDecoratorTests {
// ensure some send time elapses
Thread.sleep(sendTimeLimit + 100);
TextMessage payload = new TextMessage("payload");
concurrentSession.sendMessage(payload);
assertFalse(blockingSession.isOpen());
try {
TextMessage payload = new TextMessage("payload");
concurrentSession.sendMessage(payload);
fail("Expected exception");
}
catch (SessionLimitExceededException ex) {
}
}
@Test
@@ -174,8 +178,12 @@ public class ConcurrentWebSocketSessionDecoratorTests {
assertEquals(1023, concurrentSession.getBufferSize());
assertTrue(blockingSession.isOpen());
concurrentSession.sendMessage(message);
assertFalse(blockingSession.isOpen());
try {
concurrentSession.sendMessage(message);
fail("Expected exception");
}
catch (SessionLimitExceededException ex) {
}
}
@@ -217,4 +225,47 @@ public class ConcurrentWebSocketSessionDecoratorTests {
}
}
// @Test
// public void sendSessionLimitException() throws IOException, InterruptedException {
//
// BlockingSession blockingSession = new BlockingSession();
// blockingSession.setOpen(true);
// CountDownLatch sentMessageLatch = blockingSession.getSentMessageLatch();
//
// int sendTimeLimit = 10 * 1000;
// int bufferSizeLimit = 1024;
//
// final ConcurrentWebSocketSessionDecorator concurrentSession =
// new ConcurrentWebSocketSessionDecorator(blockingSession, sendTimeLimit, bufferSizeLimit);
//
// Executors.newSingleThreadExecutor().submit(new Runnable() {
// @Override
// public void run() {
// TextMessage textMessage = new TextMessage("slow message");
// try {
// concurrentSession.sendMessage(textMessage);
// }
// catch (IOException e) {
// e.printStackTrace();
// }
// }
// });
//
// assertTrue(sentMessageLatch.await(5, TimeUnit.SECONDS));
//
// StringBuilder sb = new StringBuilder();
// for (int i=0 ; i < 1023; i++) {
// sb.append("a");
// }
//
// TextMessage message = new TextMessage(sb.toString());
// concurrentSession.sendMessage(message);
//
// assertEquals(1023, concurrentSession.getBufferSize());
// assertTrue(blockingSession.isOpen());
//
// concurrentSession.sendMessage(message);
// assertFalse(blockingSession.isOpen());
// }
}