Skip to content

Commit 382231a

Browse files
committed
impl: Add the roaming state to ActiveConnection
In some of the use cases, I needed the active connection to keep living after the server thread that spawned it went out of scope. This change makes it possible by adding a new state called 'roaming' which allows the server (or any other owner) to skip closing the instance.
1 parent 45d1a8a commit 382231a

File tree

5 files changed

+140
-10
lines changed

5 files changed

+140
-10
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>org.monora.coolsocket</groupId>
77
<artifactId>core</artifactId>
8-
<version>2.0-rc16</version>
8+
<version>2.0-rc17</version>
99
<name>CoolSocket</name>
1010
<description>Bidirectional TCP socket layer and server</description>
1111
<url>https://github.com/libcoolsocket</url>
@@ -175,4 +175,4 @@
175175
<scope>compile</scope>
176176
</dependency>
177177
</dependencies>
178-
</project>
178+
</project>

src/main/java/org/monora/coolsocket/core/server/DefaultConnectionManager.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,11 @@ public void handleClient(@NotNull CoolSocket coolSocket, final @NotNull ActiveCo
7676
} catch (Exception e) {
7777
coolSocket.getLogger().log(Level.SEVERE, "An error occurred during handling of a client", e);
7878
} finally {
79-
try {
80-
activeConnection.close();
81-
} catch (IOException ignored) {
79+
if (!activeConnection.isRoaming()) {
80+
try {
81+
activeConnection.close();
82+
} catch (IOException ignored) {
83+
}
8284
}
8385

8486
synchronized (connectionList) {

src/main/java/org/monora/coolsocket/core/session/ActiveConnection.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public class ActiveConnection implements Closeable
4242

4343
private boolean closeRequested;
4444

45+
private boolean roaming = false;
46+
4547
/**
4648
* Create an instance with a socket connection to a CoolSocket server.
4749
*
@@ -412,6 +414,33 @@ else if (protocolVersion == 0) {
412414
handleProtocolRequest(description, write);
413415
}
414416

417+
/**
418+
* Check whether the roaming state is activated for this instance.
419+
* <p>
420+
* When in that state, connections won't be closed by their owners when they go out of scope.
421+
* <p>
422+
* For instance, a {@link CoolSocket} server will not {@link #close()} an instance after its child thread exits,
423+
* allowing to you keep using the connection without having to block that child thread.
424+
*
425+
* @return True if the roaming is activated.
426+
* @see #setRoaming(boolean)
427+
*/
428+
public boolean isRoaming()
429+
{
430+
return roaming;
431+
}
432+
433+
/**
434+
* Change the roaming state of this instance.
435+
*
436+
* @param roaming True to enable the roaming state.
437+
* @see #isRoaming()
438+
*/
439+
public void setRoaming(boolean roaming)
440+
{
441+
this.roaming = roaming;
442+
}
443+
415444
/**
416445
* Read from the remote. This reads into the {@link Description#byteBuffer} and returns the length of the bytes
417446
* read.
@@ -1127,4 +1156,4 @@ public long totalLength()
11271156
return totalLength;
11281157
}
11291158
}
1130-
}
1159+
}

src/test/java/org/monora/coolsocket/core/PlainTransactionTest.java

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
import org.junit.Test;
77
import org.monora.coolsocket.core.response.Response;
88
import org.monora.coolsocket.core.session.ActiveConnection;
9-
import org.monora.coolsocket.core.variant.BlockingCoolSocket;
10-
import org.monora.coolsocket.core.variant.Connections;
11-
import org.monora.coolsocket.core.variant.DefaultCoolSocket;
12-
import org.monora.coolsocket.core.variant.StaticMessageCoolSocket;
9+
import org.monora.coolsocket.core.variant.*;
1310

1411
import java.io.IOException;
12+
import java.net.SocketException;
1513

1614
public class PlainTransactionTest
1715
{
@@ -169,4 +167,69 @@ public void onConnected(@NotNull ActiveConnection activeConnection)
169167
coolSocket.stop();
170168
}
171169
}
170+
171+
@Test(timeout = 10000)
172+
public void roamingChildTest() throws IOException, InterruptedException
173+
{
174+
final String message = "Hello, World!";
175+
176+
RoamingChildCoolSocket coolSocket = new RoamingChildCoolSocket(true);
177+
Thread thread = new Thread(() -> {
178+
try {
179+
ActiveConnection activeConnection = coolSocket.connectionsQueue.take();
180+
CoolSocket.Session session = coolSocket.getSession();
181+
182+
Assert.assertNotNull("Session should not be null", session);
183+
184+
while (true) {
185+
if (session.getConnectionManager().getActiveConnectionList().size() < 1) break;
186+
}
187+
188+
activeConnection.reply(message);
189+
} catch (InterruptedException | IOException e) {
190+
e.printStackTrace();
191+
}
192+
});
193+
194+
coolSocket.start();
195+
196+
try (ActiveConnection activeConnection = Connections.connect()) {
197+
thread.start();
198+
Assert.assertEquals("The messages should match", message, activeConnection.receive().getAsString());
199+
} finally {
200+
coolSocket.stop();
201+
}
202+
}
203+
204+
@Test(expected = SocketException.class, timeout = 10000)
205+
public void nonRoamingChildClosesTest() throws IOException, InterruptedException
206+
{
207+
final String message = "Foo";
208+
209+
RoamingChildCoolSocket coolSocket = new RoamingChildCoolSocket(false);
210+
Thread thread = new Thread(() -> {
211+
try {
212+
ActiveConnection activeConnection = coolSocket.connectionsQueue.take();
213+
CoolSocket.Session session = coolSocket.getSession();
214+
215+
Assert.assertNotNull("Session should not be null", session);
216+
217+
while (true) {
218+
if (session.getConnectionManager().getActiveConnectionList().size() < 1) break;
219+
}
220+
221+
activeConnection.reply(message);
222+
} catch (InterruptedException | IOException ignored) {
223+
}
224+
});
225+
226+
coolSocket.start();
227+
228+
try (ActiveConnection activeConnection = Connections.connect()) {
229+
thread.start();
230+
Assert.assertEquals("The messages should match", message, activeConnection.receive().getAsString());
231+
} finally {
232+
coolSocket.stop();
233+
}
234+
}
172235
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.monora.coolsocket.core.variant;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
import org.monora.coolsocket.core.CoolSocket;
5+
import org.monora.coolsocket.core.session.ActiveConnection;
6+
import org.monora.coolsocket.core.variant.factory.TestConfigFactory;
7+
8+
import java.util.concurrent.BlockingQueue;
9+
import java.util.concurrent.SynchronousQueue;
10+
11+
public class RoamingChildCoolSocket extends CoolSocket
12+
{
13+
public final BlockingQueue<ActiveConnection> connectionsQueue = new SynchronousQueue<>();
14+
15+
public final boolean roamingEnabled;
16+
17+
public RoamingChildCoolSocket(boolean roamingEnabled)
18+
{
19+
super(new TestConfigFactory());
20+
this.roamingEnabled = roamingEnabled;
21+
}
22+
23+
@Override
24+
public void onConnected(@NotNull ActiveConnection activeConnection)
25+
{
26+
if (roamingEnabled) {
27+
activeConnection.setRoaming(true);
28+
}
29+
30+
try {
31+
connectionsQueue.put(activeConnection);
32+
} catch (InterruptedException e) {
33+
e.printStackTrace();
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)