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