From 28f644bf25b80a6642ce1f32f1688a8d8f4c7cca Mon Sep 17 00:00:00 2001 From: Arpit Agarwal Date: Tue, 27 Feb 2018 07:38:29 -0800 Subject: [PATCH] HADOOP-15178. Generalize NetUtils#wrapException to handle other subclasses with String Constructor. Contributed by Ajay Kumar. --- .../java/org/apache/hadoop/net/NetUtils.java | 163 +++++++++--------- .../org/apache/hadoop/net/TestNetUtils.java | 40 +++++ 2 files changed, 125 insertions(+), 78 deletions(-) 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 4697320a801..e16c2a3d370 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 @@ -715,9 +715,9 @@ public class NetUtils { * return an IOException with the input exception as the cause and also * include the host details. The new exception provides the stack trace of the * place where the exception is thrown and some extra diagnostics information. - * If the exception is BindException or ConnectException or - * UnknownHostException or SocketTimeoutException, return a new one of the - * same type; Otherwise return an IOException. + * If the exception is of type BindException, ConnectException, + * UnknownHostException, SocketTimeoutException or has a String constructor, + * return a new one of the same type; Otherwise return an IOException. * * @param destHost target host (nullable) * @param destPort target port @@ -731,83 +731,90 @@ public class NetUtils { final String localHost, final int localPort, final IOException exception) { - if (exception instanceof BindException) { - return wrapWithMessage(exception, - "Problem binding to [" - + localHost - + ":" - + localPort - + "] " - + exception - + ";" - + see("BindException")); - } else if (exception instanceof ConnectException) { - // Check if client was trying to connect to an unspecified IPv4 address - // (0.0.0.0) or IPv6 address(0:0:0:0:0:0:0:0 or ::) - if ((destHost != null && (destHost.equals("0.0.0.0") || - destHost.equals("0:0:0:0:0:0:0:0") || destHost.equals("::"))) - || destPort == 0) { - return wrapWithMessage(exception, "Your endpoint configuration" + - " is wrong;" + see("UnsetHostnameOrPort")); - } else { - // connection refused; include the host:port in the error + try { + if (exception instanceof BindException) { return wrapWithMessage(exception, - "Call From " + "Problem binding to [" + localHost - + " to " - + destHost + ":" - + destPort - + " failed on connection exception: " + + localPort + + "] " + exception + ";" - + see("ConnectionRefused")); - } - } else if (exception instanceof UnknownHostException) { - return wrapWithMessage(exception, - "Invalid host name: " - + getHostDetailsAsString(destHost, destPort, localHost) - + exception - + ";" - + see("UnknownHost")); - } else if (exception instanceof SocketTimeoutException) { - return wrapWithMessage(exception, - "Call From " - + localHost + " to " + destHost + ":" + destPort - + " failed on socket timeout exception: " + exception - + ";" - + see("SocketTimeout")); - } else if (exception instanceof NoRouteToHostException) { - return wrapWithMessage(exception, - "No Route to Host from " - + localHost + " to " + destHost + ":" + destPort - + " failed on socket timeout exception: " + exception - + ";" - + see("NoRouteToHost")); - } else if (exception instanceof EOFException) { - return wrapWithMessage(exception, - "End of File Exception between " - + getHostDetailsAsString(destHost, destPort, localHost) - + ": " + exception - + ";" - + see("EOFException")); - } else if (exception instanceof SocketException) { - // Many of the predecessor exceptions are subclasses of SocketException, - // so must be handled before this - return wrapWithMessage(exception, - "Call From " - + localHost + " to " + destHost + ":" + destPort - + " failed on socket exception: " + exception - + ";" - + see("SocketException")); - } - else { - return (IOException) new IOException("Failed on local exception: " - + exception - + "; Host Details : " - + getHostDetailsAsString(destHost, destPort, localHost)) - .initCause(exception); + + see("BindException")); + } else if (exception instanceof ConnectException) { + // Check if client was trying to connect to an unspecified IPv4 address + // (0.0.0.0) or IPv6 address(0:0:0:0:0:0:0:0 or ::) + if ((destHost != null && (destHost.equals("0.0.0.0") || + destHost.equals("0:0:0:0:0:0:0:0") || destHost.equals("::"))) + || destPort == 0) { + return wrapWithMessage(exception, "Your endpoint configuration" + + " is wrong;" + see("UnsetHostnameOrPort")); + } else { + // connection refused; include the host:port in the error + return wrapWithMessage(exception, + "Call From " + + localHost + + " to " + + destHost + + ":" + + destPort + + " failed on connection exception: " + + exception + + ";" + + see("ConnectionRefused")); + } + } else if (exception instanceof UnknownHostException) { + return wrapWithMessage(exception, + "Invalid host name: " + + getHostDetailsAsString(destHost, destPort, localHost) + + exception + + ";" + + see("UnknownHost")); + } else if (exception instanceof SocketTimeoutException) { + return wrapWithMessage(exception, + "Call From " + + localHost + " to " + destHost + ":" + destPort + + " failed on socket timeout exception: " + exception + + ";" + + see("SocketTimeout")); + } else if (exception instanceof NoRouteToHostException) { + return wrapWithMessage(exception, + "No Route to Host from " + + localHost + " to " + destHost + ":" + destPort + + " failed on socket timeout exception: " + exception + + ";" + + see("NoRouteToHost")); + } else if (exception instanceof EOFException) { + return wrapWithMessage(exception, + "End of File Exception between " + + getHostDetailsAsString(destHost, destPort, localHost) + + ": " + exception + + ";" + + see("EOFException")); + } else if (exception instanceof SocketException) { + // Many of the predecessor exceptions are subclasses of SocketException, + // so must be handled before this + return wrapWithMessage(exception, + "Call From " + + localHost + " to " + destHost + ":" + destPort + + " failed on socket exception: " + exception + + ";" + + see("SocketException")); + } else { + // Return instance of same type if Exception has a String constructor + return wrapWithMessage(exception, + "DestHost:destPort " + destHost + ":" + destPort + + " , LocalHost:localPort " + localHost + + ":" + localPort + ". Failed on local exception: " + + exception); + } + } catch (IOException ex) { + return (IOException) new IOException("Failed on local exception: " + + exception + "; Host Details : " + + getHostDetailsAsString(destHost, destPort, localHost)) + .initCause(exception); } } @@ -817,16 +824,16 @@ public class NetUtils { @SuppressWarnings("unchecked") private static T wrapWithMessage( - T exception, String msg) { + T exception, String msg) throws T { Class clazz = exception.getClass(); try { Constructor ctor = clazz.getConstructor(String.class); Throwable t = ctor.newInstance(msg); return (T)(t.initCause(exception)); } catch (Throwable e) { - LOG.warn("Unable to wrap exception of type " + - clazz + ": it has no (String) constructor", e); - return exception; + LOG.warn("Unable to wrap exception of type {}: it has no (String) " + + "constructor", clazz, e); + throw exception; } } 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 fc1c10254f4..b463c959dad 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 @@ -32,6 +32,7 @@ import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URI; import java.net.UnknownHostException; +import java.nio.charset.CharacterCodingException; import java.util.Arrays; import java.util.Enumeration; import java.util.List; @@ -40,6 +41,7 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.io.IOUtils; +import org.apache.hadoop.security.KerberosAuthException; import org.apache.hadoop.security.NetUtilsTestResolver; import org.junit.Assume; import org.junit.Before; @@ -262,6 +264,44 @@ public class TestNetUtils { assertInException(wrapped, "/EOFException"); } + @Test + public void testWrapKerbAuthException() throws Throwable { + IOException e = new KerberosAuthException("socket timeout on connection"); + IOException wrapped = verifyExceptionClass(e, KerberosAuthException.class); + assertInException(wrapped, "socket timeout on connection"); + assertInException(wrapped, "localhost"); + assertInException(wrapped, "DestHost:destPort "); + assertInException(wrapped, "LocalHost:localPort"); + assertRemoteDetailsIncluded(wrapped); + assertInException(wrapped, "KerberosAuthException"); + } + + @Test + public void testWrapIOEWithNoStringConstructor() throws Throwable { + IOException e = new CharacterCodingException(); + IOException wrapped = verifyExceptionClass(e, IOException.class); + assertInException(wrapped, "Failed on local exception"); + assertNotInException(wrapped, NetUtils.HADOOP_WIKI); + assertInException(wrapped, "Host Details "); + assertRemoteDetailsIncluded(wrapped); + } + + @Test + public void testWrapIOEWithPrivateStringConstructor() throws Throwable { + class TestIOException extends CharacterCodingException{ + private TestIOException(String cause){ + } + TestIOException(){ + } + } + IOException e = new TestIOException(); + IOException wrapped = verifyExceptionClass(e, IOException.class); + assertInException(wrapped, "Failed on local exception"); + assertNotInException(wrapped, NetUtils.HADOOP_WIKI); + assertInException(wrapped, "Host Details "); + assertRemoteDetailsIncluded(wrapped); + } + @Test public void testWrapSocketException() throws Throwable { IOException wrapped = verifyExceptionClass(new SocketException("failed"),