From f6d5dd3f62f01a0d2ce48d5f925eefadf00c77d6 Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Fri, 13 Mar 2015 15:54:47 +0100 Subject: [PATCH] JVMCBC-171: Make sure nodesExt without hostname is backwards compatible. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Motivation ---------- Couchbase Server versions prior to 3.0.2 do not include the hostname in the nodesExt config part. In 2.1.1 a regression was introduced which expected it to be there and therefore broke backwards compatibility. Modifications ------------- The code now grabs the hostname from the nodes section if it is not available in nodesExt. A test has been added to make sure it works properly. Result ------ Backwards compatbible behaviour with server versions older than 3.0.2. Change-Id: I89b3230826103fb6dc1da94d72674ff23366d22e Reviewed-on: http://review.couchbase.org/48238 Tested-by: Michael Nitschinger Reviewed-by: Simon Baslé --- .../core/config/AbstractBucketConfig.java | 16 ++++++++++++---- .../client/core/config/DefaultNodeInfo.java | 14 +++++++++++--- .../client/core/config/DefaultPortInfo.java | 17 ++++++++++------- .../DefaultCouchbaseBucketConfigTest.java | 12 ++++++++++++ .../core/config/nodes_ext_without_hostname.json | 2 ++ 5 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 src/test/resources/com/couchbase/client/core/config/nodes_ext_without_hostname.json diff --git a/src/main/java/com/couchbase/client/core/config/AbstractBucketConfig.java b/src/main/java/com/couchbase/client/core/config/AbstractBucketConfig.java index 5b8e5dc1..68fc3f68 100644 --- a/src/main/java/com/couchbase/client/core/config/AbstractBucketConfig.java +++ b/src/main/java/com/couchbase/client/core/config/AbstractBucketConfig.java @@ -23,6 +23,7 @@ import com.couchbase.client.core.service.ServiceType; +import java.net.InetAddress; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -44,7 +45,7 @@ protected AbstractBucketConfig(String name, BucketNodeLocator locator, String ur this.locator = locator; this.uri = uri; this.streamingUri = streamingUri; - this.nodeInfo = portInfos == null ? nodeInfos : nodeInfoFromExtended(portInfos); + this.nodeInfo = portInfos == null ? nodeInfos : nodeInfoFromExtended(portInfos, nodeInfos); this.enabledServices = new HashSet(); for (NodeInfo info : nodeInfo) { @@ -56,13 +57,20 @@ protected AbstractBucketConfig(String name, BucketNodeLocator locator, String ur /** * Helper method to create the {@link NodeInfo}s from from the extended node information. * + * In older server versions (< 3.0.2) the nodesExt part does not carry a hostname, so as a fallback the hostname + * is loaded from the node info if needed. + * * @param nodesExt the extended information. * @return the generated node infos. */ - private static List nodeInfoFromExtended(final List nodesExt) { + private static List nodeInfoFromExtended(final List nodesExt, final List nodeInfos) { List converted = new ArrayList(nodesExt.size()); - for (PortInfo nodeExt : nodesExt) { - converted.add(new DefaultNodeInfo(nodeExt.hostname(), nodeExt.ports(), nodeExt.sslPorts())); + for (int i = 0; i < nodesExt.size(); i++) { + InetAddress hostname = nodesExt.get(i).hostname(); + if (hostname == null) { + hostname = nodeInfos.get(i).hostname(); + } + converted.add(new DefaultNodeInfo(hostname, nodesExt.get(i).ports(), nodesExt.get(i).sslPorts())); } return converted; } diff --git a/src/main/java/com/couchbase/client/core/config/DefaultNodeInfo.java b/src/main/java/com/couchbase/client/core/config/DefaultNodeInfo.java index 5cba536e..6f5c81d3 100644 --- a/src/main/java/com/couchbase/client/core/config/DefaultNodeInfo.java +++ b/src/main/java/com/couchbase/client/core/config/DefaultNodeInfo.java @@ -54,9 +54,13 @@ public class DefaultNodeInfo implements NodeInfo { */ @JsonCreator public DefaultNodeInfo( - @JsonProperty("couchApiBase") String viewUri, - @JsonProperty("hostname") String hostname, - @JsonProperty("ports") Map ports) { + @JsonProperty("couchApiBase") String viewUri, + @JsonProperty("hostname") String hostname, + @JsonProperty("ports") Map ports) { + if (hostname == null) { + throw new CouchbaseException(new IllegalArgumentException("NodeInfo hostname cannot be null")); + } + try { this.hostname = InetAddress.getByName(trimPort(hostname)); } catch (UnknownHostException e) { @@ -75,6 +79,10 @@ public DefaultNodeInfo( */ public DefaultNodeInfo(InetAddress hostname, Map direct, Map ssl) { + if (hostname == null) { + throw new CouchbaseException(new IllegalArgumentException("NodeInfo hostname cannot be null")); + } + this.hostname = hostname; this.directServices = direct; this.sslServices = ssl; diff --git a/src/main/java/com/couchbase/client/core/config/DefaultPortInfo.java b/src/main/java/com/couchbase/client/core/config/DefaultPortInfo.java index 6703bdca..96b64cba 100644 --- a/src/main/java/com/couchbase/client/core/config/DefaultPortInfo.java +++ b/src/main/java/com/couchbase/client/core/config/DefaultPortInfo.java @@ -40,17 +40,20 @@ public class DefaultPortInfo implements PortInfo { /** * Creates a new {@link DefaultPortInfo}. * + * Note that if the hostname is null (not provided by the server), it is explicitly set to null because otherwise + * the loaded InetAddress would point to localhost. + * * @param services the list of services mapping to ports. */ @JsonCreator public DefaultPortInfo( - @JsonProperty("services") Map services, - @JsonProperty("hostname") String hostname + @JsonProperty("services") Map services, + @JsonProperty("hostname") String hostname ) { ports = new HashMap(); sslPorts = new HashMap(); try { - this.hostname = InetAddress.getByName(hostname); + this.hostname = hostname == null ? null : InetAddress.getByName(hostname); } catch (UnknownHostException e) { throw new CouchbaseException("Could not analyze hostname from config.", e); } @@ -96,9 +99,9 @@ public InetAddress hostname() { @Override public String toString() { return "DefaultPortInfo{" - + "ports=" + ports - + ", sslPorts=" + sslPorts - + ", hostname='" + hostname - + '\'' + '}'; + + "ports=" + ports + + ", sslPorts=" + sslPorts + + ", hostname='" + hostname + + '\'' + '}'; } } diff --git a/src/test/java/com/couchbase/client/core/config/DefaultCouchbaseBucketConfigTest.java b/src/test/java/com/couchbase/client/core/config/DefaultCouchbaseBucketConfigTest.java index 77dee1da..ea2d88b9 100644 --- a/src/test/java/com/couchbase/client/core/config/DefaultCouchbaseBucketConfigTest.java +++ b/src/test/java/com/couchbase/client/core/config/DefaultCouchbaseBucketConfigTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import java.net.InetAddress; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -42,4 +43,15 @@ public void shouldHavePrimaryPartitionsOnNode() throws Exception { assertTrue(config.hasPrimaryPartitionsOnNode(InetAddress.getByName("1.2.3.4"))); assertFalse(config.hasPrimaryPartitionsOnNode(InetAddress.getByName("2.3.4.5"))); } + + @Test + public void shouldFallbackToNodeHostnameIfNotInNodesExt() throws Exception { + String raw = Resources.read("nodes_ext_without_hostname.json", getClass()); + CouchbaseBucketConfig config = JSON_MAPPER.readValue(raw, CouchbaseBucketConfig.class); + + InetAddress expected = InetAddress.getByName("1.2.3.4"); + assertEquals(1, config.nodes().size()); + assertEquals(expected, config.nodes().get(0).hostname()); + + } } \ No newline at end of file diff --git a/src/test/resources/com/couchbase/client/core/config/nodes_ext_without_hostname.json b/src/test/resources/com/couchbase/client/core/config/nodes_ext_without_hostname.json new file mode 100644 index 00000000..b2c5f08f --- /dev/null +++ b/src/test/resources/com/couchbase/client/core/config/nodes_ext_without_hostname.json @@ -0,0 +1,2 @@ + +{"rev":12,"name":"default","uri":"/pools/default/buckets/default?bucket_uuid=b181c77269c99cc9942ddfeccc5faf70","streamingUri":"/pools/default/bucketsStreaming/default?bucket_uuid=b181c77269c99cc9942ddfeccc5faf70","nodes":[{"couchApiBase":"http://1.2.3.4:8092/default%2Bb181c77269c99cc9942ddfeccc5faf70","hostname":"1.2.3.4:8091","ports":{"proxy":11211,"direct":11210}}],"nodesExt":[{"services":{"mgmt":8091,"capi":8092,"moxi":11211,"kv":11210,"kvSSL":11207,"capiSSL":18092,"mgmtSSL":18091}}],"nodeLocator":"vbucket","uuid":"b181c77269c99cc9942ddfeccc5faf70","ddocs":{"uri":"/pools/default/buckets/default/ddocs"},"vBucketServerMap":{"hashAlgorithm":"CRC","numReplicas":1,"serverList":["1.2.3.4:11210"],"vBucketMap":[[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1]]},"bucketCapabilitiesVer":"","bucketCapabilities":["cbhello","touch","couchapi","cccp","xdcrCheckpointing","nodesExt"]} \ No newline at end of file