001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.ipc; 019 020import java.io.IOException; 021import java.lang.reflect.Constructor; 022import java.security.AccessController; 023import java.security.PrivilegedAction; 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.hbase.DoNotRetryIOException; 026import org.apache.hadoop.hbase.HBaseConfiguration; 027import org.apache.hadoop.hbase.util.DynamicClassLoader; 028import org.apache.hadoop.ipc.RemoteException; 029import org.apache.yetus.audience.InterfaceAudience; 030 031/** 032 * A {@link RemoteException} with some extra information. If source exception was a 033 * {@link org.apache.hadoop.hbase.DoNotRetryIOException}, {@link #isDoNotRetry()} will return true. 034 * <p> 035 * A {@link RemoteException} hosts exceptions we got from the server. 036 */ 037@SuppressWarnings("serial") 038@InterfaceAudience.Public 039public class RemoteWithExtrasException extends RemoteException { 040 private final String hostname; 041 private final int port; 042 private final boolean doNotRetry; 043 044 /** 045 * Dynamic class loader to load filter/comparators 046 */ 047 private final static class ClassLoaderHolder { 048 private final static ClassLoader CLASS_LOADER; 049 050 static { 051 ClassLoader parent = RemoteWithExtrasException.class.getClassLoader(); 052 Configuration conf = HBaseConfiguration.create(); 053 CLASS_LOADER = AccessController 054 .doPrivileged((PrivilegedAction<ClassLoader>) () -> new DynamicClassLoader(conf, parent)); 055 } 056 } 057 058 public RemoteWithExtrasException(String className, String msg, final boolean doNotRetry) { 059 this(className, msg, null, -1, doNotRetry); 060 } 061 062 public RemoteWithExtrasException(String className, String msg, final String hostname, 063 final int port, final boolean doNotRetry) { 064 super(className, msg); 065 this.hostname = hostname; 066 this.port = port; 067 this.doNotRetry = doNotRetry; 068 } 069 070 @Override 071 public IOException unwrapRemoteException() { 072 Class<?> realClass; 073 try { 074 // try to load a exception class from where the HBase classes are loaded or from Dynamic 075 // classloader. 076 realClass = Class.forName(getClassName(), false, ClassLoaderHolder.CLASS_LOADER); 077 } catch (ClassNotFoundException cnfe) { 078 try { 079 // cause could be a hadoop exception, try to load from hadoop classpath 080 realClass = Class.forName(getClassName(), false, super.getClass().getClassLoader()); 081 } catch (ClassNotFoundException e) { 082 return new DoNotRetryIOException( 083 "Unable to load exception received from server:" + e.getMessage(), this); 084 } 085 } 086 try { 087 return instantiateException(realClass.asSubclass(IOException.class)); 088 } catch (Exception e) { 089 return new DoNotRetryIOException( 090 "Unable to instantiate exception received from server:" + e.getMessage(), this); 091 } 092 } 093 094 private IOException instantiateException(Class<? extends IOException> cls) throws Exception { 095 Constructor<? extends IOException> cn = cls.getConstructor(String.class); 096 cn.setAccessible(true); 097 IOException ex = cn.newInstance(this.getMessage()); 098 ex.initCause(this); 099 return ex; 100 } 101 102 /** Returns null if not set */ 103 public String getHostname() { 104 return this.hostname; 105 } 106 107 /** Returns -1 if not set */ 108 public int getPort() { 109 return this.port; 110 } 111 112 /** Returns True if origin exception was a do not retry type. */ 113 public boolean isDoNotRetry() { 114 return this.doNotRetry; 115 } 116}