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 {