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 
19 package org.apache.hadoop.ipc;
20 
21 import java.io.IOException;
22 import java.lang.reflect.Constructor;
23 
24 import org.xml.sax.Attributes;
25 
26 public class RemoteException extends IOException {
27   /** For java.io.Serializable */
28   private static final long serialVersionUID = 1L;
29 
30   private String className;
31 
RemoteException(String className, String msg)32   public RemoteException(String className, String msg) {
33     super(msg);
34     this.className = className;
35   }
36 
getClassName()37   public String getClassName() {
38     return className;
39   }
40 
41   /**
42    * If this remote exception wraps up one of the lookupTypes
43    * then return this exception.
44    * <p>
45    * Unwraps any IOException.
46    *
47    * @param lookupTypes the desired exception class.
48    * @return IOException, which is either the lookupClass exception or this.
49    */
unwrapRemoteException(Class<?>.... lookupTypes)50   public IOException unwrapRemoteException(Class<?>... lookupTypes) {
51     if(lookupTypes == null)
52       return this;
53     for(Class<?> lookupClass : lookupTypes) {
54       if(!lookupClass.getName().equals(getClassName()))
55         continue;
56       try {
57         return instantiateException(lookupClass.asSubclass(IOException.class));
58       } catch(Exception e) {
59         // cannot instantiate lookupClass, just return this
60         return this;
61       }
62     }
63     // wrapped up exception is not in lookupTypes, just return this
64     return this;
65   }
66 
67   /**
68    * Instantiate and return the exception wrapped up by this remote exception.
69    *
70    * <p> This unwraps any <code>Throwable</code> that has a constructor taking
71    * a <code>String</code> as a parameter.
72    * Otherwise it returns this.
73    *
74    * @return <code>Throwable
75    */
unwrapRemoteException()76   public IOException unwrapRemoteException() {
77     try {
78       Class<?> realClass = Class.forName(getClassName());
79       return instantiateException(realClass.asSubclass(IOException.class));
80     } catch(Exception e) {
81       // cannot instantiate the original exception, just return this
82     }
83     return this;
84   }
85 
instantiateException(Class<? extends IOException> cls)86   private IOException instantiateException(Class<? extends IOException> cls)
87       throws Exception {
88     Constructor<? extends IOException> cn = cls.getConstructor(String.class);
89     cn.setAccessible(true);
90     String firstLine = this.getMessage();
91     int eol = firstLine.indexOf('\n');
92     if (eol>=0) {
93       firstLine = firstLine.substring(0, eol);
94     }
95     IOException ex = cn.newInstance(firstLine);
96     ex.initCause(this);
97     return ex;
98   }
99 
100   /** Create RemoteException from attributes */
valueOf(Attributes attrs)101   public static RemoteException valueOf(Attributes attrs) {
102     return new RemoteException(attrs.getValue("class"),
103         attrs.getValue("message"));
104   }
105 }
106