diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditor.java index 8e3dddbda..32383ba49 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditor.java @@ -16,12 +16,14 @@ package org.springframework.data.mongodb.config; import java.beans.PropertyEditorSupport; +import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import com.mongodb.ServerAddress; @@ -35,6 +37,11 @@ import com.mongodb.ServerAddress; */ public class ServerAddressPropertyEditor extends PropertyEditorSupport { + /** + * A port is a number without a leading 0 at the end of the address that is proceeded by just a single :. + */ + private static final String HOST_PORT_SPLIT_PATTERN = "(? 2) { - LOG.warn("Could not parse address source '{}'. Check your replica set configuration!", source); + if (hostAndPort.length > 2) { + LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "source", source); return null; } try { - return hostAndPort.length == 1 ? new ServerAddress(hostAndPort[0]) : new ServerAddress(hostAndPort[0], - Integer.parseInt(hostAndPort[1])); + InetAddress hostAddress = InetAddress.getByName(hostAndPort[0]); + Integer port = hostAndPort.length == 1 ? null : Integer.parseInt(hostAndPort[1]); + + return port == null ? new ServerAddress(hostAddress) : new ServerAddress(hostAddress, port); } catch (UnknownHostException e) { - LOG.warn("Could not parse host '{}'. Check your replica set configuration!", hostAndPort[0]); + LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "host", hostAndPort[0]); } catch (NumberFormatException e) { - LOG.warn("Could not parse port '{}'. Check your replica set configuration!", hostAndPort[1]); + LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "port", hostAndPort[1]); } return null; } + + /** + * Extract the host and port from the given {@link String}. + * + * @param addressAndPortSource must not be {@literal null}. + * @return + */ + private String[] extractHostAddressAndPort(String addressAndPortSource) { + + Assert.notNull(addressAndPortSource, "Address and port source must not be null!"); + + String[] hostAndPort = addressAndPortSource.split(HOST_PORT_SPLIT_PATTERN); + String hostAddress = hostAndPort[0]; + + if (isHostAddressInIPv6BracketNotation(hostAddress)) { + hostAndPort[0] = hostAddress.substring(1, hostAddress.length() - 1); + } + + return hostAndPort; + } + + private boolean isHostAddressInIPv6BracketNotation(String hostAddress) { + return hostAddress.startsWith("[") && hostAddress.endsWith("]"); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests.java index 975812f77..f3e15aec4 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoNamespaceReplicaSetTests.java @@ -19,6 +19,7 @@ package org.springframework.data.mongodb.config; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import java.net.InetAddress; import java.util.List; import org.junit.Ignore; @@ -40,8 +41,7 @@ import com.mongodb.ServerAddress; @ContextConfiguration public class MongoNamespaceReplicaSetTests { - @Autowired - private ApplicationContext ctx; + @Autowired private ApplicationContext ctx; @Test @SuppressWarnings("unchecked") @@ -53,7 +53,10 @@ public class MongoNamespaceReplicaSetTests { List replicaSetSeeds = (List) ReflectionTestUtils.getField(mfb, "replicaSetSeeds"); assertThat(replicaSetSeeds, is(notNullValue())); - assertThat(replicaSetSeeds, hasItems(new ServerAddress("127.0.0.1", 10001), new ServerAddress("localhost", 10002))); + assertThat( + replicaSetSeeds, + hasItems(new ServerAddress(InetAddress.getByName("127.0.0.1"), 10001), + new ServerAddress(InetAddress.getByName("localhost"), 10002))); } @Test diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditorUnitTests.java index baf688f86..2d7607ed6 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ServerAddressPropertyEditorUnitTests.java @@ -18,12 +18,15 @@ package org.springframework.data.mongodb.config; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collection; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import com.mongodb.ServerAddress; @@ -35,6 +38,8 @@ import com.mongodb.ServerAddress; */ public class ServerAddressPropertyEditorUnitTests { + @Rule public ExpectedException expectedException = ExpectedException.none(); + ServerAddressPropertyEditor editor; @Before @@ -81,11 +86,111 @@ public class ServerAddressPropertyEditorUnitTests { assertNull(editor.getValue()); } + /** + * @see DATAMONGO-808 + */ + @Test + public void handleIPv6HostaddressLoopbackShort() throws UnknownHostException { + + String hostAddress = "::1"; + editor.setAsText(hostAddress); + + assertSingleAddressWithPort(hostAddress, null, editor.getValue()); + } + + /** + * @see DATAMONGO-808 + */ + @Test + public void handleIPv6HostaddressLoopbackShortWithPort() throws UnknownHostException { + + String hostAddress = "::1"; + int port = 27017; + editor.setAsText(hostAddress + ":" + port); + + assertSingleAddressWithPort(hostAddress, port, editor.getValue()); + } + + /** + * Here we detect no port since the last segment of the address contains leading zeros. + * + * @see DATAMONGO-808 + */ + @Test + public void handleIPv6HostaddressLoopbackLong() throws UnknownHostException { + + String hostAddress = "0000:0000:0000:0000:0000:0000:0000:0001"; + editor.setAsText(hostAddress); + + assertSingleAddressWithPort(hostAddress, null, editor.getValue()); + } + + /** + * @see DATAMONGO-808 + */ + @Test + public void handleIPv6HostaddressLoopbackLongWithBrackets() throws UnknownHostException { + + String hostAddress = "[0000:0000:0000:0000:0000:0000:0000:0001]"; + editor.setAsText(hostAddress); + + assertSingleAddressWithPort(hostAddress, null, editor.getValue()); + } + + /** + * We can't tell whether the last part of the hostAddress represents a port or not. + * + * @see DATAMONGO-808 + */ + @Test + public void shouldFailToHandleAmbiguousIPv6HostaddressLongWithoutPortAndWithoutBrackets() throws UnknownHostException { + + expectedException.expect(IllegalArgumentException.class); + + String hostAddress = "0000:0000:0000:0000:0000:0000:0000:128"; + editor.setAsText(hostAddress); + } + + /** + * @see DATAMONGO-808 + */ + @Test + public void handleIPv6HostaddressExampleAddressWithPort() throws UnknownHostException { + + String hostAddress = "0000:0000:0000:0000:0000:0000:0000:0001"; + int port = 27017; + editor.setAsText(hostAddress + ":" + port); + + assertSingleAddressWithPort(hostAddress, port, editor.getValue()); + } + + /** + * @see DATAMONGO-808 + */ + @Test + public void handleIPv6HostaddressExampleAddressInBracketsWithPort() throws UnknownHostException { + + String hostAddress = "[0000:0000:0000:0000:0000:0000:0000:0001]"; + int port = 27017; + editor.setAsText(hostAddress + ":" + port); + + assertSingleAddressWithPort(hostAddress, port, editor.getValue()); + } + private static void assertSingleAddressOfLocalhost(Object result) throws UnknownHostException { + assertSingleAddressWithPort("localhost", null, result); + } + + private static void assertSingleAddressWithPort(String hostAddress, Integer port, Object result) + throws UnknownHostException { assertThat(result, is(instanceOf(ServerAddress[].class))); Collection addresses = Arrays.asList((ServerAddress[]) result); assertThat(addresses, hasSize(1)); - assertThat(addresses, hasItem(new ServerAddress("localhost"))); + if (port == null) { + assertThat(addresses, hasItem(new ServerAddress(InetAddress.getByName(hostAddress)))); + } else { + assertThat(addresses, hasItem(new ServerAddress(InetAddress.getByName(hostAddress), port))); + } } }