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.procedure2; 019 020import java.io.IOException; 021 022import org.apache.hadoop.ipc.RemoteException; 023import org.apache.yetus.audience.InterfaceAudience; 024import org.apache.hadoop.hbase.shaded.protobuf.generated.ErrorHandlingProtos.ForeignExceptionMessage; 025import org.apache.hadoop.hbase.util.ForeignExceptionUtil; 026 027/** 028 * A RemoteProcedureException is an exception from another thread or process. 029 * <p> 030 * RemoteProcedureExceptions are sent to 'remote' peers to signal an abort in the face of failures. 031 * When serialized for transmission we encode using Protobufs to ensure version compatibility. 032 * <p> 033 * RemoteProcedureException exceptions contain a Throwable as its cause. 034 * This can be a "regular" exception generated locally or a ProxyThrowable that is a representation 035 * of the original exception created on original 'remote' source. These ProxyThrowables have their 036 * their stacks traces and messages overridden to reflect the original 'remote' exception. 037 */ 038@InterfaceAudience.Private 039@SuppressWarnings("serial") 040public class RemoteProcedureException extends ProcedureException { 041 042 /** 043 * Name of the throwable's source such as a host or thread name. Must be non-null. 044 */ 045 private final String source; 046 047 /** 048 * Create a new RemoteProcedureException that can be serialized. 049 * It is assumed that this came form a local source. 050 * @param source 051 * @param cause 052 */ 053 public RemoteProcedureException(String source, Throwable cause) { 054 super(cause); 055 assert source != null; 056 assert cause != null; 057 this.source = source; 058 } 059 060 public String getSource() { 061 return source; 062 } 063 064 public Exception unwrapRemoteException() { 065 final Throwable cause = getCause(); 066 if (cause instanceof RemoteException) { 067 return ((RemoteException)cause).unwrapRemoteException(); 068 } 069 if (cause instanceof Exception) { 070 return (Exception)cause; 071 } 072 return new Exception(cause); 073 } 074 075 // NOTE: Does not throw DoNotRetryIOE because it does not 076 // have access (DNRIOE is in the client module). Use 077 // MasterProcedureUtil.unwrapRemoteIOException if need to 078 // throw DNRIOE. 079 public IOException unwrapRemoteIOException() { 080 final Exception cause = unwrapRemoteException(); 081 if (cause instanceof IOException) { 082 return (IOException)cause; 083 } 084 return new IOException(cause); 085 } 086 087 @Override 088 public String toString() { 089 String className = getCause().getClass().getName(); 090 return className + " via " + getSource() + ":" + getLocalizedMessage(); 091 } 092 093 /** 094 * Converts a RemoteProcedureException to an array of bytes. 095 * @param source the name of the external exception source 096 * @param t the "local" external exception (local) 097 * @return protobuf serialized version of RemoteProcedureException 098 */ 099 public static byte[] serialize(String source, Throwable t) { 100 return toProto(source, t).toByteArray(); 101 } 102 103 /** 104 * Takes a series of bytes and tries to generate an RemoteProcedureException instance for it. 105 * @param bytes 106 * @return the ForeignExcpetion instance 107 * @throws InvalidProtocolBufferException if there was deserialization problem this is thrown. 108 */ 109 public static RemoteProcedureException deserialize(byte[] bytes) throws IOException { 110 return fromProto(ForeignExceptionMessage.parseFrom(bytes)); 111 } 112 113 public ForeignExceptionMessage convert() { 114 return ForeignExceptionUtil.toProtoForeignException(getSource(), getCause()); 115 } 116 117 public static ForeignExceptionMessage toProto(String source, Throwable t) { 118 return ForeignExceptionUtil.toProtoForeignException(source, t); 119 } 120 121 public static RemoteProcedureException fromProto(final ForeignExceptionMessage eem) { 122 return new RemoteProcedureException(eem.getSource(), ForeignExceptionUtil.toException(eem)); 123 } 124}