diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index 16c67fd3da0..8d72310a0a0 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -403,6 +403,9 @@ Release 0.23.0 - Unreleased HADOOP-7705. Add a log4j back end that can push out JSON data, one per line. (stevel) + HADOOP-7749. Add a NetUtils createSocketAddr call which provides more + help in exception messages. (todd) + OPTIMIZATIONS HADOOP-7333. Performance improvement in PureJavaCrc32. (Eric Caspole diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java index c151d8c6a18..8755f129384 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetUtils.java @@ -150,12 +150,38 @@ public class NetUtils { */ public static InetSocketAddress createSocketAddr(String target, int defaultPort) { + return createSocketAddr(target, defaultPort, null); + } + + /** + * Create an InetSocketAddress from the given target string and + * default port. If the string cannot be parsed correctly, the + * configName parameter is used as part of the + * exception message, allowing the user to better diagnose + * the misconfiguration. + * + * @param target a string of either "host" or "host:port" + * @param defaultPort the default port if target does not + * include a port number + * @param configName the name of the configuration from which + * target was loaded. This is used in the + * exception message in the case that parsing fails. + */ + public static InetSocketAddress createSocketAddr(String target, + int defaultPort, + String configName) { + String helpText = ""; + if (configName != null) { + helpText = " (configuration property '" + configName + "')"; + } if (target == null) { - throw new IllegalArgumentException("Target address cannot be null."); + throw new IllegalArgumentException("Target address cannot be null." + + helpText); } int colonIndex = target.indexOf(':'); if (colonIndex < 0 && defaultPort == -1) { - throw new RuntimeException("Not a host:port pair: " + target); + throw new RuntimeException("Not a host:port pair: " + target + + helpText); } String hostname; int port = -1; @@ -165,7 +191,14 @@ public class NetUtils { } else { // must be the old style : hostname = target.substring(0, colonIndex); - port = Integer.parseInt(target.substring(colonIndex + 1)); + String portStr = target.substring(colonIndex + 1); + try { + port = Integer.parseInt(portStr); + } catch (NumberFormatException nfe) { + throw new IllegalArgumentException( + "Can't parse port '" + portStr + "'" + + helpText); + } } } else { // a new uri diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java index a28d853ac74..dfa3a9d0490 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestNetUtils.java @@ -131,6 +131,27 @@ public class TestNetUtils { assertRemoteDetailsIncluded(wrapped); assertInException(wrapped, "/UnknownHost"); } + + @Test + public void testCreateSocketAddress() throws Throwable { + InetSocketAddress addr = NetUtils.createSocketAddr( + "127.0.0.1:12345", 1000, "myconfig"); + assertEquals("127.0.0.1", addr.getAddress().getHostAddress()); + assertEquals(12345, addr.getPort()); + + addr = NetUtils.createSocketAddr( + "127.0.0.1", 1000, "myconfig"); + assertEquals("127.0.0.1", addr.getAddress().getHostAddress()); + assertEquals(1000, addr.getPort()); + + try { + addr = NetUtils.createSocketAddr( + "127.0.0.1:blahblah", 1000, "myconfig"); + fail("Should have failed to parse bad port"); + } catch (IllegalArgumentException iae) { + assertInException(iae, "myconfig"); + } + } private void assertRemoteDetailsIncluded(IOException wrapped) throws Throwable {