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 */ 018 019 package org.apache.hadoop.lib.lang; 020 021 import org.apache.hadoop.classification.InterfaceAudience; 022 import org.apache.hadoop.lib.util.Check; 023 024 import java.text.MessageFormat; 025 026 /** 027 * Generic exception that requires error codes and uses the a message 028 * template from the error code. 029 */ 030 @InterfaceAudience.Private 031 public class XException extends Exception { 032 033 /** 034 * Interface to define error codes. 035 */ 036 public static interface ERROR { 037 038 /** 039 * Returns the template for the error. 040 * 041 * @return the template for the error, the template must be in JDK 042 * <code>MessageFormat</code> syntax (using {#} positional parameters). 043 */ 044 public String getTemplate(); 045 046 } 047 048 private ERROR error; 049 050 /** 051 * Private constructor used by the public constructors. 052 * 053 * @param error error code. 054 * @param message error message. 055 * @param cause exception cause if any. 056 */ 057 private XException(ERROR error, String message, Throwable cause) { 058 super(message, cause); 059 this.error = error; 060 } 061 062 /** 063 * Creates an XException using another XException as cause. 064 * <p/> 065 * The error code and error message are extracted from the cause. 066 * 067 * @param cause exception cause. 068 */ 069 public XException(XException cause) { 070 this(cause.getError(), cause.getMessage(), cause); 071 } 072 073 /** 074 * Creates an XException using the specified error code. The exception 075 * message is resolved using the error code template and the passed 076 * parameters. 077 * 078 * @param error error code for the XException. 079 * @param params parameters to use when creating the error message 080 * with the error code template. 081 */ 082 @SuppressWarnings({"ThrowableResultOfMethodCallIgnored"}) 083 public XException(ERROR error, Object... params) { 084 this(Check.notNull(error, "error"), format(error, params), getCause(params)); 085 } 086 087 /** 088 * Returns the error code of the exception. 089 * 090 * @return the error code of the exception. 091 */ 092 public ERROR getError() { 093 return error; 094 } 095 096 /** 097 * Creates a message using a error message template and arguments. 098 * <p/> 099 * The template must be in JDK <code>MessageFormat</code> syntax 100 * (using {#} positional parameters). 101 * 102 * @param error error code, to get the template from. 103 * @param args arguments to use for creating the message. 104 * 105 * @return the resolved error message. 106 */ 107 private static String format(ERROR error, Object... args) { 108 String template = error.getTemplate(); 109 if (template == null) { 110 StringBuilder sb = new StringBuilder(); 111 for (int i = 0; i < args.length; i++) { 112 sb.append(" {").append(i).append("}"); 113 } 114 template = sb.deleteCharAt(0).toString(); 115 } 116 return error + ": " + MessageFormat.format(template, args); 117 } 118 119 /** 120 * Returns the last parameter if it is an instance of <code>Throwable</code> 121 * returns it else it returns NULL. 122 * 123 * @param params parameters to look for a cause. 124 * 125 * @return the last parameter if it is an instance of <code>Throwable</code> 126 * returns it else it returns NULL. 127 */ 128 private static Throwable getCause(Object... params) { 129 Throwable throwable = null; 130 if (params != null && params.length > 0 && params[params.length - 1] instanceof Throwable) { 131 throwable = (Throwable) params[params.length - 1]; 132 } 133 return throwable; 134 } 135 136 }