diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7eab29a48..b9af3671f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,7 @@
# Change Log
-## Version 2.7.0
+## Version 2.8.0
- [ADDED] #323 Nats.connect v2 credentials (@olicuzo)
- [CHANGED] #320 Update MAINTAINERS.md (@gcolliso)
diff --git a/README.md b/README.md
index ae1a0d5cf..e60d05875 100644
--- a/README.md
+++ b/README.md
@@ -52,9 +52,9 @@ The java-nats client is provided in a single jar file, with a single external de
### Downloading the Jar
-You can download the latest jar at [https://search.maven.org/remotecontent?filepath=io/nats/jnats/2.7.0/jnats-2.7.0.jar](https://search.maven.org/remotecontent?filepath=io/nats/jnats/2.7.0/jnats-2.7.0.jar).
+You can download the latest jar at [https://search.maven.org/remotecontent?filepath=io/nats/jnats/2.8.0/jnats-2.8.0.jar](https://search.maven.org/remotecontent?filepath=io/nats/jnats/2.8.0/jnats-2.8.0.jar).
-The examples are available at [https://search.maven.org/remotecontent?filepath=io/nats/jnats/2.7.0/jnats-2.7.0-examples.jar](https://search.maven.org/remotecontent?filepath=io/nats/jnats/2.7.0/jnats-2.7.0-examples.jar).
+The examples are available at [https://search.maven.org/remotecontent?filepath=io/nats/jnats/2.8.0/jnats-2.8.0-examples.jar](https://search.maven.org/remotecontent?filepath=io/nats/jnats/2.8.0/jnats-2.8.0-examples.jar).
To use NKeys, you will need the ed25519 library, which can be downloaded at [https://repo1.maven.org/maven2/net/i2p/crypto/eddsa/0.3.0/eddsa-0.3.0.jar](https://repo1.maven.org/maven2/net/i2p/crypto/eddsa/0.3.0/eddsa-0.3.0.jar).
@@ -64,7 +64,7 @@ The NATS client is available in the Maven central repository, and can be importe
```groovy
dependencies {
- implementation 'io.nats:jnats:2.7.0'
+ implementation 'io.nats:jnats:2.8.0'
}
```
@@ -90,7 +90,7 @@ The NATS client is available on the Maven central repository, and can be importe
io.nats
jnats
- 2.7.0
+ 2.8.0
```
diff --git a/build.gradle b/build.gradle
index e6cdb3832..34ef6cb18 100644
--- a/build.gradle
+++ b/build.gradle
@@ -15,10 +15,10 @@ plugins {
// Update version here, repeated check-ins not into master will have snapshot on them
// Be sure to update Nats.java with the latest version, the change log and the package-info.java
def versionMajor = 2
-def versionMinor = 7
+def versionMinor = 8
def versionPatch = 0
def versionModifier = ""
-def jarVersion = "2.7.0"
+def jarVersion = "2.8.0"
def branch = System.getenv("TRAVIS_BRANCH") != null ? System.getenv("TRAVIS_BRANCH") : "";
def tag = System.getenv("TRAVIS_TAG") != null ? System.getenv("TRAVIS_TAG") : "";
def useSigning = "master".equals(branch) || (!"".equals(tag) && tag.equals(branch)) // tag will be the branch on a tag event for travis
diff --git a/src/main/java/io/nats/client/ConnectionListener.java b/src/main/java/io/nats/client/ConnectionListener.java
index 0e0b9818a..0dcc93bd7 100644
--- a/src/main/java/io/nats/client/ConnectionListener.java
+++ b/src/main/java/io/nats/client/ConnectionListener.java
@@ -30,7 +30,9 @@ public enum Events {
/** The connection was reconnected and the server has been notified of all subscriptions. */
RESUBSCRIBED("nats: subscriptions re-established"),
/** The connection was told about new servers from, from the current server. */
- DISCOVERED_SERVERS("nats: discovered servers");
+ DISCOVERED_SERVERS("nats: discovered servers"),
+ /** Server Sent a lame duck mode. */
+ LAME_DUCK("nats: lame duck mode");
private String event;
diff --git a/src/main/java/io/nats/client/Nats.java b/src/main/java/io/nats/client/Nats.java
index a8fa75bb9..225fa9075 100644
--- a/src/main/java/io/nats/client/Nats.java
+++ b/src/main/java/io/nats/client/Nats.java
@@ -72,7 +72,7 @@ public class Nats {
/**
* Current version of the library - {@value #CLIENT_VERSION}
*/
- public static final String CLIENT_VERSION = "2.7.0";
+ public static final String CLIENT_VERSION = "2.8.0";
/**
* Current language of the library - {@value #CLIENT_LANGUAGE}
diff --git a/src/main/java/io/nats/client/impl/NatsConnection.java b/src/main/java/io/nats/client/impl/NatsConnection.java
index db4e10c82..21e783369 100644
--- a/src/main/java/io/nats/client/impl/NatsConnection.java
+++ b/src/main/java/io/nats/client/impl/NatsConnection.java
@@ -1344,6 +1344,10 @@ void handleInfo(String infoJson) {
if (urls != null && urls.length > 0) {
processConnectionEvent(Events.DISCOVERED_SERVERS);
}
+
+ if (serverInfo.isLameDuckMode()) {
+ processConnectionEvent(Events.LAME_DUCK);
+ }
}
void queueOutgoing(NatsMessage msg) {
diff --git a/src/main/java/io/nats/client/impl/NatsServerInfo.java b/src/main/java/io/nats/client/impl/NatsServerInfo.java
index 48fb2ec12..ee493e100 100644
--- a/src/main/java/io/nats/client/impl/NatsServerInfo.java
+++ b/src/main/java/io/nats/client/impl/NatsServerInfo.java
@@ -31,6 +31,7 @@ class NatsServerInfo {
static final String CONNECT_URLS = "connect_urls";
static final String PROTOCOL_VERSION = "proto";
static final String NONCE = "nonce";
+ static final String LAME_DUCK_MODE = "ldm";
private String serverId;
private String version;
@@ -44,12 +45,17 @@ class NatsServerInfo {
private String rawInfoJson;
private int protocolVersion;
private byte[] nonce;
+ private boolean lameDuckMode;
public NatsServerInfo(String json) {
this.rawInfoJson = json;
parseInfo(json);
}
+ public boolean isLameDuckMode() {
+ return lameDuckMode;
+ }
+
public String getServerId() {
return this.serverId;
}
@@ -106,6 +112,7 @@ public String getRawJson() {
private static final String grabObject = "\\{(.+?)\\}";
void parseInfo(String jsonString) {
+ Pattern lameDuckMode = Pattern.compile("\""+LAME_DUCK_MODE+"\":" + grabBoolean, Pattern.CASE_INSENSITIVE);
Pattern serverIdRE = Pattern.compile("\""+SERVER_ID+"\":" + grabString, Pattern.CASE_INSENSITIVE);
Pattern versionRE = Pattern.compile("\""+VERSION+"\":" + grabString, Pattern.CASE_INSENSITIVE);
Pattern goRE = Pattern.compile("\""+GO+"\":" + grabString, Pattern.CASE_INSENSITIVE);
@@ -168,7 +175,13 @@ void parseInfo(String jsonString) {
if (m.find()) {
this.tlsRequired = Boolean.parseBoolean(m.group(1));
}
-
+
+ m = lameDuckMode.matcher(jsonString);
+ if (m.find()) {
+ this.lameDuckMode = Boolean.parseBoolean(m.group(1));
+ }
+
+
m = portRE.matcher(jsonString);
if (m.find()) {
this.port = Integer.parseInt(m.group(1));
diff --git a/src/test/java/io/nats/client/impl/InfoHandlerTests.java b/src/test/java/io/nats/client/impl/InfoHandlerTests.java
index 90e865a69..52360b646 100644
--- a/src/test/java/io/nats/client/impl/InfoHandlerTests.java
+++ b/src/test/java/io/nats/client/impl/InfoHandlerTests.java
@@ -13,18 +13,16 @@
package io.nats.client.impl;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import io.nats.client.*;
import org.junit.Test;
-import io.nats.client.Connection;
-import io.nats.client.NatsServerProtocolMock;
-import io.nats.client.Nats;
+import static org.junit.Assert.*;
public class InfoHandlerTests {
@Test
@@ -44,6 +42,8 @@ public void testInitialInfo() throws IOException, InterruptedException {
}
}
+
+
@Test
public void testUnsolicitedInfo() throws IOException, InterruptedException, ExecutionException {
String customInfo = "{\"server_id\":\"myid\"}";
@@ -103,4 +103,79 @@ public void testUnsolicitedInfo() throws IOException, InterruptedException, Exec
}
}
}
+
+
+
+ @Test
+ public void testLDM() throws IOException, InterruptedException, ExecutionException, TimeoutException {
+ String customInfo = "{\"server_id\":\"myid\", \"ldm\":true}";
+ CompletableFuture gotPong = new CompletableFuture<>();
+ CompletableFuture sendInfo = new CompletableFuture<>();
+ CompletableFuture connectLDM = new CompletableFuture<>();
+
+ NatsServerProtocolMock.Customizer infoCustomizer = (ts, r, w) -> {
+
+ // Wait for client to be ready.
+ try {
+ sendInfo.get();
+ } catch (Exception e) {
+ // return, we will fail the test
+ gotPong.cancel(true);
+ return;
+ }
+
+ System.out.println("*** Mock Server @" + ts.getPort() + " sending INFO ...");
+ w.write("INFO {\"server_id\":\"replacement\"}\r\n");
+ w.flush();
+
+ System.out.println("*** Mock Server @" + ts.getPort() + " sending PING ...");
+ w.write("PING\r\n");
+ w.flush();
+
+ String pong = "";
+
+ System.out.println("*** Mock Server @" + ts.getPort() + " waiting for PONG ...");
+ try {
+ pong = r.readLine();
+ } catch (Exception e) {
+ gotPong.cancel(true);
+ return;
+ }
+
+ if (pong != null && pong.startsWith("PONG")) {
+ System.out.println("*** Mock Server @" + ts.getPort() + " got PONG ...");
+ gotPong.complete(Boolean.TRUE);
+ } else {
+ System.out.println("*** Mock Server @" + ts.getPort() + " got something else... " + pong);
+ gotPong.complete(Boolean.FALSE);
+ }
+ };
+
+ try (NatsServerProtocolMock ts = new NatsServerProtocolMock(infoCustomizer, customInfo)) {
+
+ Options options = new Options.Builder().server(ts.getURI()).connectionListener(new ConnectionListener() {
+ @Override
+ public void connectionEvent(Connection conn, Events type) {
+ if (type.equals(Events.LAME_DUCK)) connectLDM.complete(type);
+ }
+ }).build();
+
+ Connection nc = Nats.connect(options);
+ try {
+ assertTrue("Connected Status", Connection.Status.CONNECTED == nc.getStatus());
+ assertEquals("got custom info", "myid", ((NatsConnection) nc).getInfo().getServerId());
+ sendInfo.complete(Boolean.TRUE);
+
+ assertTrue("Got pong.", gotPong.get().booleanValue()); // Server round tripped so we should have new info
+ assertEquals("got replacement info", "replacement", ((NatsConnection) nc).getInfo().getServerId());
+ } finally {
+ nc.close();
+ assertTrue("Closed Status", Connection.Status.CLOSED == nc.getStatus());
+ }
+ }
+
+ ConnectionListener.Events event = connectLDM.get(5, TimeUnit.SECONDS);
+ assertEquals(event, ConnectionListener.Events.LAME_DUCK);
+ System.out.println(event);
+ }
}
\ No newline at end of file