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; 024 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.hbase.DoNotRetryIOException; 027import org.apache.hadoop.hbase.HBaseConfiguration; 028import org.apache.yetus.audience.InterfaceAudience; 029import org.apache.hadoop.hbase.protobuf.ProtobufUtil; 030import org.apache.hadoop.hbase.util.DynamicClassLoader; 031import org.apache.hadoop.ipc.RemoteException; 032 033/** 034 * A {@link RemoteException} with some extra information. If source exception 035 * was a {@link org.apache.hadoop.hbase.DoNotRetryIOException}, 036 * {@link #isDoNotRetry()} will return true. 037 * <p>A {@link RemoteException} hosts exceptions we got from the server. 038 */ 039@SuppressWarnings("serial") 040@InterfaceAudience.Public 041public class RemoteWithExtrasException extends RemoteException { 042 private final String hostname; 043 private final int port; 044 private final boolean doNotRetry; 045 046 /** 047 * Dynamic class loader to load filter/comparators 048 */ 049 private final static class ClassLoaderHolder { 050 private final static ClassLoader CLASS_LOADER; 051 052 static { 053 ClassLoader parent = RemoteWithExtrasException.class.getClassLoader(); 054 Configuration conf = HBaseConfiguration.create(); 055 CLASS_LOADER = AccessController.doPrivileged((PrivilegedAction<ClassLoader>) 056 () -> new DynamicClassLoader(conf, parent) 057 ); 058 } 059 } 060 061 public RemoteWithExtrasException(String className, String msg, final boolean doNotRetry) { 062 this(className, msg, null, -1, doNotRetry); 063 } 064 065 public RemoteWithExtrasException(String className, String msg, final String hostname, 066 final int port, final boolean doNotRetry) { 067 super(className, msg); 068 this.hostname = hostname; 069 this.port = port; 070 this.doNotRetry = doNotRetry; 071 } 072 073 @Override 074 public IOException unwrapRemoteException() { 075 Class<?> realClass; 076 try { 077 // try to load a exception class from where the HBase classes are loaded or from Dynamic 078 // classloader. 079 realClass = Class.forName(getClassName(), false, ClassLoaderHolder.CLASS_LOADER); 080 } catch (ClassNotFoundException cnfe) { 081 try { 082 // cause could be a hadoop exception, try to load from hadoop classpath 083 realClass = Class.forName(getClassName(), false, super.getClass().getClassLoader()); 084 } catch (ClassNotFoundException e) { 085 return new DoNotRetryIOException( 086 "Unable to load exception received from server:" + e.getMessage(), this); 087 } 088 } 089 try { 090 return instantiateException(realClass.asSubclass(IOException.class)); 091 } catch (Exception e) { 092 return new DoNotRetryIOException( 093 "Unable to instantiate exception received from server:" + e.getMessage(), this); 094 } 095 } 096 097 private IOException instantiateException(Class<? extends IOException> cls) throws Exception { 098 Constructor<? extends IOException> cn = cls.getConstructor(String.class); 099 cn.setAccessible(true); 100 IOException ex = cn.newInstance(this.getMessage()); 101 ex.initCause(this); 102 return ex; 103 } 104 105 /** 106 * @return null if not set 107 */ 108 public String getHostname() { 109 return this.hostname; 110 } 111 112 /** 113 * @return -1 if not set 114 */ 115 public int getPort() { 116 return this.port; 117 } 118 119 /** 120 * @return True if origin exception was a do not retry type. 121 */ 122 public boolean isDoNotRetry() { 123 return this.doNotRetry; 124 } 125}