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