HADOOP-15178. Generalize NetUtils#wrapException to handle other subclasses with String Constructor. Contributed by Ajay Kumar.

This commit is contained in:
Arpit Agarwal 2018-02-27 07:38:29 -08:00
parent 1e85a995d1
commit 28f644bf25
2 changed files with 125 additions and 78 deletions

View File

@ -715,9 +715,9 @@ public class NetUtils {
* return an IOException with the input exception as the cause and also * 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 * include the host details. The new exception provides the stack trace of the
* place where the exception is thrown and some extra diagnostics information. * place where the exception is thrown and some extra diagnostics information.
* If the exception is BindException or ConnectException or * If the exception is of type BindException, ConnectException,
* UnknownHostException or SocketTimeoutException, return a new one of the * UnknownHostException, SocketTimeoutException or has a String constructor,
* same type; Otherwise return an IOException. * return a new one of the same type; Otherwise return an IOException.
* *
* @param destHost target host (nullable) * @param destHost target host (nullable)
* @param destPort target port * @param destPort target port
@ -731,83 +731,90 @@ public class NetUtils {
final String localHost, final String localHost,
final int localPort, final int localPort,
final IOException exception) { final IOException exception) {
if (exception instanceof BindException) { try {
return wrapWithMessage(exception, if (exception instanceof BindException) {
"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
return wrapWithMessage(exception, return wrapWithMessage(exception,
"Call From " "Problem binding to ["
+ localHost + localHost
+ " to "
+ destHost
+ ":" + ":"
+ destPort + localPort
+ " failed on connection exception: " + "] "
+ exception + exception
+ ";" + ";"
+ see("ConnectionRefused")); + see("BindException"));
} } else if (exception instanceof ConnectException) {
} else if (exception instanceof UnknownHostException) { // Check if client was trying to connect to an unspecified IPv4 address
return wrapWithMessage(exception, // (0.0.0.0) or IPv6 address(0:0:0:0:0:0:0:0 or ::)
"Invalid host name: " if ((destHost != null && (destHost.equals("0.0.0.0") ||
+ getHostDetailsAsString(destHost, destPort, localHost) destHost.equals("0:0:0:0:0:0:0:0") || destHost.equals("::")))
+ exception || destPort == 0) {
+ ";" return wrapWithMessage(exception, "Your endpoint configuration" +
+ see("UnknownHost")); " is wrong;" + see("UnsetHostnameOrPort"));
} else if (exception instanceof SocketTimeoutException) { } else {
return wrapWithMessage(exception, // connection refused; include the host:port in the error
"Call From " return wrapWithMessage(exception,
+ localHost + " to " + destHost + ":" + destPort "Call From "
+ " failed on socket timeout exception: " + exception + localHost
+ ";" + " to "
+ see("SocketTimeout")); + destHost
} else if (exception instanceof NoRouteToHostException) { + ":"
return wrapWithMessage(exception, + destPort
"No Route to Host from " + " failed on connection exception: "
+ localHost + " to " + destHost + ":" + destPort + exception
+ " failed on socket timeout exception: " + exception + ";"
+ ";" + see("ConnectionRefused"));
+ see("NoRouteToHost")); }
} else if (exception instanceof EOFException) { } else if (exception instanceof UnknownHostException) {
return wrapWithMessage(exception, return wrapWithMessage(exception,
"End of File Exception between " "Invalid host name: "
+ getHostDetailsAsString(destHost, destPort, localHost) + getHostDetailsAsString(destHost, destPort, localHost)
+ ": " + exception + exception
+ ";" + ";"
+ see("EOFException")); + see("UnknownHost"));
} else if (exception instanceof SocketException) { } else if (exception instanceof SocketTimeoutException) {
// Many of the predecessor exceptions are subclasses of SocketException, return wrapWithMessage(exception,
// so must be handled before this "Call From "
return wrapWithMessage(exception, + localHost + " to " + destHost + ":" + destPort
"Call From " + " failed on socket timeout exception: " + exception
+ localHost + " to " + destHost + ":" + destPort + ";"
+ " failed on socket exception: " + exception + see("SocketTimeout"));
+ ";" } else if (exception instanceof NoRouteToHostException) {
+ see("SocketException")); return wrapWithMessage(exception,
} "No Route to Host from "
else { + localHost + " to " + destHost + ":" + destPort
return (IOException) new IOException("Failed on local exception: " + " failed on socket timeout exception: " + exception
+ exception + ";"
+ "; Host Details : " + see("NoRouteToHost"));
+ getHostDetailsAsString(destHost, destPort, localHost)) } else if (exception instanceof EOFException) {
.initCause(exception); 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") @SuppressWarnings("unchecked")
private static <T extends IOException> T wrapWithMessage( private static <T extends IOException> T wrapWithMessage(
T exception, String msg) { T exception, String msg) throws T {
Class<? extends Throwable> clazz = exception.getClass(); Class<? extends Throwable> clazz = exception.getClass();
try { try {
Constructor<? extends Throwable> ctor = clazz.getConstructor(String.class); Constructor<? extends Throwable> ctor = clazz.getConstructor(String.class);
Throwable t = ctor.newInstance(msg); Throwable t = ctor.newInstance(msg);
return (T)(t.initCause(exception)); return (T)(t.initCause(exception));
} catch (Throwable e) { } catch (Throwable e) {
LOG.warn("Unable to wrap exception of type " + LOG.warn("Unable to wrap exception of type {}: it has no (String) "
clazz + ": it has no (String) constructor", e); + "constructor", clazz, e);
return exception; throw exception;
} }
} }

View File

@ -32,6 +32,7 @@ import java.net.SocketException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URI; import java.net.URI;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.charset.CharacterCodingException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
@ -40,6 +41,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.security.KerberosAuthException;
import org.apache.hadoop.security.NetUtilsTestResolver; import org.apache.hadoop.security.NetUtilsTestResolver;
import org.junit.Assume; import org.junit.Assume;
import org.junit.Before; import org.junit.Before;
@ -262,6 +264,44 @@ public class TestNetUtils {
assertInException(wrapped, "/EOFException"); 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 @Test
public void testWrapSocketException() throws Throwable { public void testWrapSocketException() throws Throwable {
IOException wrapped = verifyExceptionClass(new SocketException("failed"), IOException wrapped = verifyExceptionClass(new SocketException("failed"),