diff --git a/pom.xml b/pom.xml
index ae5273b..8286d1a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,24 +55,24 @@
org.slf4j
slf4j-api
- 2.0.9
+ 2.0.13
org.slf4j
slf4j-simple
- 2.0.9
+ 2.0.13
test
io.muserver
mu-server
- 0.74.3
+ 1.1.0
provided
org.json
json
- 20231013
+ 20240303
test
@@ -90,7 +90,7 @@
org.junit.jupiter
junit-jupiter
- 5.10.1
+ 5.10.2
test
@@ -109,7 +109,7 @@
com.hsbc.cranker
cranker-connector
- 1.2.3
+ 1.2.4
test
diff --git a/src/main/java/com/hsbc/cranker/mucranker/ConnectorConnection.java b/src/main/java/com/hsbc/cranker/mucranker/ConnectorConnection.java
index 21597a8..5879705 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/ConnectorConnection.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/ConnectorConnection.java
@@ -9,16 +9,19 @@
public interface ConnectorConnection {
/**
+ * A unique ID of this socket
* @return A unique ID of this socket
*/
String socketID();
/**
+ * The port the socket is connected on
* @return The port the socket is connected on
*/
int port();
/**
+ * the data in this object as a map
* @return Returns the data in this object as a map
*/
HashMap toMap();
diff --git a/src/main/java/com/hsbc/cranker/mucranker/ConnectorInstance.java b/src/main/java/com/hsbc/cranker/mucranker/ConnectorInstance.java
index 0d5c81e..92641a1 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/ConnectorInstance.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/ConnectorInstance.java
@@ -13,26 +13,31 @@
public interface ConnectorInstance {
/**
+ * The IP address of the instance.
* @return The IP address of the instance.
*/
String ip();
/**
+ * The unique ID of the connector.
* @return The unique ID of the connector.
*/
String connectorInstanceID();
/**
+ * The current idle connections that this connector has registered to the router.
* @return The current idle connections that this connector has registered to the router.
*/
List connections();
/**
+ * Dark mode status
* @return Returns true
if this connector is on a dark mode host; otherwise false
.
*/
boolean darkMode();
/**
+ * The state of this object as a map of key-value pairs.
* @return Returns the state of this object as a map of key-value pairs.
*/
Map toMap();
diff --git a/src/main/java/com/hsbc/cranker/mucranker/ConnectorService.java b/src/main/java/com/hsbc/cranker/mucranker/ConnectorService.java
index ee09034..66c8d75 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/ConnectorService.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/ConnectorService.java
@@ -13,27 +13,32 @@
public interface ConnectorService {
/**
+ * The path prefix of the service.
* @return The path prefix of the service, or "*" if it is a catch-all service.
* @see #isCatchAll()
*/
String route();
/**
+ * The component name that the connector registered
* @return The component name that the connector registered
*/
String componentName();
/**
+ * The connectors that serve this route.
* @return The connectors that serve this route.
*/
List connectors();
/**
+ * If this connector serves from the root of the URL path.
* @return True if this connector serves from the root of the URL path
*/
boolean isCatchAll();
/**
+ * Gets this data has key-value pairs.
* @return Gets this data has key-value pairs.
*/
Map toMap();
diff --git a/src/main/java/com/hsbc/cranker/mucranker/CrankerRouter.java b/src/main/java/com/hsbc/cranker/mucranker/CrankerRouter.java
index 51c7949..fa9e632 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/CrankerRouter.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/CrankerRouter.java
@@ -17,6 +17,7 @@ public interface CrankerRouter {
MuHandler createRegistrationHandler();
/**
+ * The total number of websocket connections for all routes that are currently connected and ready to receive requests
* @return The total number of websocket connections for all routes that are currently connected and ready to receive requests
*/
int idleConnectionCount();
@@ -40,11 +41,13 @@ public interface CrankerRouter {
void stop();
/**
+ * A manager that allows you to stop or start requests going to specific hosts.
* @return A manager that allows you to stop or start requests going to specific hosts.
*/
DarkModeManager darkModeManager();
/**
+ * The version of mu-cranker-router being used.
* @return The version of mu-cranker-router being used, e.g. 1.0.0
*/
static String muCrankerVersion() {
diff --git a/src/main/java/com/hsbc/cranker/mucranker/CrankerRouterBuilder.java b/src/main/java/com/hsbc/cranker/mucranker/CrankerRouterBuilder.java
index 8cd45df..90c2dda 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/CrankerRouterBuilder.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/CrankerRouterBuilder.java
@@ -28,7 +28,10 @@ public class CrankerRouterBuilder {
private RouteResolver routeResolver;
private List supportedCrankerProtocol = List.of("1.0", "3.0");
+ private CrankerRouterBuilder() {}
+
/**
+ * Create a CrankerRouterBuilder
* @return A new builder
*/
public static CrankerRouterBuilder crankerRouter() {
@@ -225,6 +228,7 @@ public CrankerRouterBuilder withSupportedCrankerProtocols(List protocols
/**
+ * Create a newly created CrankerRouter object
* @return A newly created CrankerRouter object
*/
public CrankerRouter start() {
diff --git a/src/main/java/com/hsbc/cranker/mucranker/DarkHost.java b/src/main/java/com/hsbc/cranker/mucranker/DarkHost.java
index 1c2a799..ea2c37b 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/DarkHost.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/DarkHost.java
@@ -16,11 +16,13 @@
public interface DarkHost {
/**
+ * The address of the host
* @return The address of the host
*/
InetAddress address();
/**
+ * The time that dark mode was turned on for this host
* @return Returns the time that dark mode was turned on for this host
*/
Instant dateEnabled();
diff --git a/src/main/java/com/hsbc/cranker/mucranker/LongestFirstRouteResolver.java b/src/main/java/com/hsbc/cranker/mucranker/LongestFirstRouteResolver.java
index 346d0f4..570d39d 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/LongestFirstRouteResolver.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/LongestFirstRouteResolver.java
@@ -7,6 +7,11 @@
*/
public class LongestFirstRouteResolver implements RouteResolver{
+ /**
+ * Constructor for LongestFirstRouteResolver
+ */
+ public LongestFirstRouteResolver() {}
+
/**
* Algorithm: using the longest route to match from the existing routes.
*
diff --git a/src/main/java/com/hsbc/cranker/mucranker/ProxyInfo.java b/src/main/java/com/hsbc/cranker/mucranker/ProxyInfo.java
index 86ade13..ee08cc8 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/ProxyInfo.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/ProxyInfo.java
@@ -13,46 +13,55 @@
public interface ProxyInfo {
/**
+ * isCatchAll
* @return Returns true if the connector is a catch-all connector (i.e. the router of the connector is '*').
*/
boolean isCatchAll();
/**
+ * A unique ID for the service connector.
* @return A unique ID for the service connector.
*/
String connectorInstanceID();
/**
+ * The address of the service connector that this request is being proxied to.
* @return The address of the service connector that this request is being proxied to.
*/
InetSocketAddress serviceAddress();
/**
+ * The cranker route (i.e. the first part of a path) for the request, or '*' if a catch-all connector is used.
* @return The cranker route (i.e. the first part of a path) for the request, or '*' if a catch-all connector is used.
*/
String route();
/**
+ * The client's request to the router.
* @return The client's request to the router.
*/
MuRequest request();
/**
+ * The router's response to the client.
* @return The router's response to the client.
*/
MuResponse response();
/**
+ * The time in millis from when the router received the request until it sent the last response byte.
* @return The time in millis from when the router received the request until it sent the last response byte.
*/
long durationMillis();
/**
+ * The number of bytes uploaded by the client in the request
* @return The number of bytes uploaded by the client in the request
*/
long bytesReceived();
/**
+ * The number of bytes sent to the client on the response
* @return The number of bytes sent to the client on the response
*/
long bytesSent();
@@ -73,6 +82,7 @@ public interface ProxyInfo {
Throwable errorIfAny();
/**
+ * Wait time in millis seconds to get a websocket (which is used for proxy requests)
* @return wait time in millis seconds to get a websocket (which is used for proxy requests)
*/
long socketWaitInMillis();
diff --git a/src/main/java/com/hsbc/cranker/mucranker/RouterInfo.java b/src/main/java/com/hsbc/cranker/mucranker/RouterInfo.java
index 07ee558..9be1951 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/RouterInfo.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/RouterInfo.java
@@ -10,6 +10,7 @@
public interface RouterInfo {
/**
+ * All the services that are registered with this cranker
* @return All the services that are registered with this cranker
*/
List services();
@@ -32,6 +33,7 @@ public interface RouterInfo {
Map toMap();
/**
+ * All the hosts that this router currently will not send requests to
* @return All the hosts that this router currently will not send requests to
*/
Set darkHosts();
diff --git a/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarm.java b/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarm.java
index c5dfec3..6791fe3 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarm.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarm.java
@@ -61,7 +61,7 @@ public void cleanRoutes(long routesKeepTimeMillis) {
final long cutoffTime = System.currentTimeMillis() - routesKeepTimeMillis;
this.sockets.entrySet().stream()
.filter(entry -> entry.getValue() != null
- && entry.getValue().size() == 0
+ && entry.getValue().isEmpty()
&& routeLastRemovalTimes.containsKey(entry.getKey())
&& routeLastRemovalTimes.get(entry.getKey()) < cutoffTime)
.forEach(entry -> {
@@ -75,7 +75,9 @@ public boolean canHandle(String target, boolean useCatchAll) {
final String routeKey = resolveRouteKey(target, useCatchAll);
if (routeKey == null) return false;
final Queue routerSockets = sockets.get(routeKey);
- return routerSockets != null && routerSockets.size() > 0;
+ if (routerSockets != null && !routerSockets.isEmpty()) return true;
+ return routeLastRemovalTimes.containsKey(routeKey)
+ && (System.currentTimeMillis() - routeLastRemovalTimes.get(routeKey) < this.maxWaitInMillis);
}
public int idleCount() {
@@ -112,7 +114,7 @@ private void addWebSocketSync(String route, RouterSocket socket) {
// if there are requests waiting for a socket to this route, then immediately pass the socket to the request
final Queue waiting = waitingTasks.get(route);
- if (waiting != null && waiting.size() > 0) {
+ if (waiting != null && !waiting.isEmpty()) {
final WaitingSocketTask waitTask = waiting.poll();
if (waitTask != null) {
waitTask.notifySuccess(socket);
@@ -253,7 +255,7 @@ static void logIfFail(ThrowingFunction f) {
}
}
- private class WaitingSocketTask {
+ private static class WaitingSocketTask {
private final String target;
private Consumer successListener;
diff --git a/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarmV3.java b/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarmV3.java
index 90a6114..91e184b 100644
--- a/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarmV3.java
+++ b/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarmV3.java
@@ -49,7 +49,7 @@ public void cleanRoutes(long routesKeepTimeMillis) {
final long cutoffTime = System.currentTimeMillis() - routesKeepTimeMillis;
this.sockets.entrySet().stream()
.filter(entry -> entry.getValue() != null
- && entry.getValue().size() == 0
+ && entry.getValue().isEmpty()
&& routeLastRemovalTimes.containsKey(entry.getKey())
&& routeLastRemovalTimes.get(entry.getKey()) < cutoffTime)
.forEach(entry -> {
@@ -63,7 +63,7 @@ public boolean canHandle(String target, boolean useCatchAll) {
final String routeKey = resolveRouteKey(target, useCatchAll);
if (routeKey == null) return false;
final List routeSockets = sockets.get(routeKey);
- return routeSockets != null && routeSockets.size() > 0;
+ return routeSockets != null && !routeSockets.isEmpty();
}
private String resolveRouteKey(String target, boolean useCatchAll) {
@@ -128,7 +128,7 @@ public CompletableFuture getWebSocket(String target, boolean use
}
List routeSockets = sockets.get(routeKey);
- if (routeSockets == null || routeSockets.size() == 0) {
+ if (routeSockets == null || routeSockets.isEmpty()) {
future.complete(null);
return;
}
diff --git a/src/test/java/RunLocal.java b/src/test/java/RunLocal.java
index a62f72f..a9c993a 100644
--- a/src/test/java/RunLocal.java
+++ b/src/test/java/RunLocal.java
@@ -5,6 +5,7 @@
import org.json.JSONObject;
import java.io.IOException;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -17,6 +18,7 @@ public static void main(String[] args) throws IOException {
// Use the mu-cranker-router builder to create a router object.
CrankerRouter router = CrankerRouterBuilder.crankerRouter()
+ .withSupportedCrankerProtocols(List.of("cranker_3.0", "cranker_1.0"))
.withIdleTimeout(5, TimeUnit.MINUTES)
.withRegistrationIpValidator(ip -> true)
.start();
diff --git a/src/test/java/com/hsbc/cranker/mucranker/MultiConnectorTest.java b/src/test/java/com/hsbc/cranker/mucranker/MultiConnectorTest.java
index 8c9a6da..550a908 100644
--- a/src/test/java/com/hsbc/cranker/mucranker/MultiConnectorTest.java
+++ b/src/test/java/com/hsbc/cranker/mucranker/MultiConnectorTest.java
@@ -205,6 +205,25 @@ void connectorCanDistributedToDifferentConnector_V1useCatchAll_V3useSpecificRout
assertThat(bodyMap.get("targetV3_1").get(), is(20));
}
+ @Test
+ void connectorCanDistributedToDifferentConnector_V3useCatchAll_V1useSpecificRouteTakeHigherPriority() {
+ // start v1 connector
+ targetV1_1 = httpServer()
+ .addHandler(Method.GET, "/my-service/hello", (request, response, pathParams) -> response.write("targetV1_1"))
+ .start();
+ connectorV1_1 = startConnector("*", "my-service", targetV1_1, List.of("cranker_1.0"));
+
+ // start another v3 connector
+ targetV3_1 = httpServer()
+ .addHandler(Method.GET, "/my-service/hello", (request, response, pathParams) -> response.write("targetV3_1"))
+ .start();
+ connectorV3_1 = startConnector("*", "*", targetV3_1, List.of("cranker_3.0"));
+
+ // specific route take higher priority
+ final HashMap bodyMap = callAndGroupByBody(router.uri().resolve("/my-service/hello"), 20, 1);
+ assertThat(bodyMap.get("targetV1_1").get(), is(20));
+ }
+
@Test
void connectorCanDistributedToDifferentConnector_V1useSpecificRouteTakeHigherPriority_V3useCatchAll() {
// start v1 connector