View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.util;
19  
20  import java.io.IOException;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import org.apache.hadoop.ipc.RemoteException;
25  import org.apache.hadoop.hbase.classification.InterfaceAudience;
26  import org.apache.hadoop.hbase.classification.InterfaceStability;
27  import org.apache.hadoop.hbase.protobuf.generated.ErrorHandlingProtos.ForeignExceptionMessage;
28  import org.apache.hadoop.hbase.protobuf.generated.ErrorHandlingProtos.GenericExceptionMessage;
29  import org.apache.hadoop.hbase.protobuf.generated.ErrorHandlingProtos.StackTraceElementMessage;
30  
31  /**
32   * Helper to convert Exceptions and StackTraces from/to protobuf.
33   * (see ErrorHandling.proto for the internal of the proto messages)
34   */
35  @InterfaceAudience.Private
36  @InterfaceStability.Evolving
37  public final class ForeignExceptionUtil {
38    private ForeignExceptionUtil() { }
39  
40    public static IOException toIOException(final ForeignExceptionMessage eem) {
41      GenericExceptionMessage gem = eem.getGenericException();
42      StackTraceElement[] trace = toStackTrace(gem.getTraceList());
43      RemoteException re = new RemoteException(gem.getClassName(), gem.getMessage());
44      re.setStackTrace(trace);
45      return re.unwrapRemoteException();
46    }
47  
48    public static ForeignExceptionMessage toProtoForeignException(String source, Throwable t) {
49      GenericExceptionMessage.Builder gemBuilder = GenericExceptionMessage.newBuilder();
50      gemBuilder.setClassName(t.getClass().getName());
51      if (t.getMessage() != null) {
52        gemBuilder.setMessage(t.getMessage());
53      }
54      // set the stack trace, if there is one
55      List<StackTraceElementMessage> stack = toProtoStackTraceElement(t.getStackTrace());
56      if (stack != null) {
57        gemBuilder.addAllTrace(stack);
58      }
59      GenericExceptionMessage payload = gemBuilder.build();
60      ForeignExceptionMessage.Builder exception = ForeignExceptionMessage.newBuilder();
61      exception.setGenericException(payload).setSource(source);
62      return exception.build();
63    }
64  
65    /**
66     * Convert a stack trace to list of {@link StackTraceElement}.
67     * @param trace the stack trace to convert to protobuf message
68     * @return <tt>null</tt> if the passed stack is <tt>null</tt>.
69     */
70    public static List<StackTraceElementMessage> toProtoStackTraceElement(StackTraceElement[] trace) {
71      // if there is no stack trace, ignore it and just return the message
72      if (trace == null) return null;
73      // build the stack trace for the message
74      List<StackTraceElementMessage> pbTrace = new ArrayList<StackTraceElementMessage>(trace.length);
75      for (StackTraceElement elem : trace) {
76        StackTraceElementMessage.Builder stackBuilder = StackTraceElementMessage.newBuilder();
77        stackBuilder.setDeclaringClass(elem.getClassName());
78        if (elem.getFileName() != null) {
79          stackBuilder.setFileName(elem.getFileName());
80        }
81        stackBuilder.setLineNumber(elem.getLineNumber());
82        stackBuilder.setMethodName(elem.getMethodName());
83        pbTrace.add(stackBuilder.build());
84      }
85      return pbTrace;
86    }
87  
88    /**
89     * Unwind a serialized array of {@link StackTraceElementMessage}s to a
90     * {@link StackTraceElement}s.
91     * @param traceList list that was serialized
92     * @return the deserialized list or <tt>null</tt> if it couldn't be unwound (e.g. wasn't set on
93     *         the sender).
94     */
95    public static StackTraceElement[] toStackTrace(List<StackTraceElementMessage> traceList) {
96      if (traceList == null || traceList.size() == 0) {
97        return new StackTraceElement[0]; // empty array
98      }
99      StackTraceElement[] trace = new StackTraceElement[traceList.size()];
100     for (int i = 0; i < traceList.size(); i++) {
101       StackTraceElementMessage elem = traceList.get(i);
102       trace[i] = new StackTraceElement(
103           elem.getDeclaringClass(), elem.getMethodName(),
104           elem.hasFileName() ? elem.getFileName() : null,
105           elem.getLineNumber());
106     }
107     return trace;
108   }
109 }