001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.rest; 014 015import static org.apache.juneau.internal.StringUtils.*; 016 017import java.lang.reflect.*; 018import java.text.*; 019 020import org.apache.juneau.http.exception.*; 021import org.apache.juneau.rest.annotation.*; 022 023/** 024 * Exception thrown to trigger an error HTTP status. 025 * 026 * <p> 027 * REST methods on subclasses of {@link RestServlet} can throw this exception to trigger an HTTP status other than the 028 * automatically-generated <c>404</c>, <c>405</c>, and <c>500</c> statuses. 029 * 030 * @deprecated Use {@link HttpException}. 031 */ 032@Deprecated 033public class RestException extends RuntimeException { 034 035 private static final long serialVersionUID = 1L; 036 037 private int status; 038 @Deprecated private int occurrence; 039 040 /** 041 * Constructor. 042 * 043 * @param cause The cause of this exception. 044 * @param status The HTTP status code. 045 * @param msg The status message. 046 * @param args Optional {@link MessageFormat}-style arguments. 047 */ 048 public RestException(Throwable cause, int status, String msg, Object...args) { 049 super(message(cause, msg, args), cause); 050 this.status = status; 051 } 052 053 /** 054 * Constructor. 055 * 056 * @param msg The status message. 057 */ 058 public RestException(String msg) { 059 super(msg, null); 060 } 061 062 private static String message(Throwable cause, String msg, Object...args) { 063 if (msg == null && cause != null) 064 return firstNonEmpty(cause.getLocalizedMessage(), cause.getClass().getName()); 065 return format(msg, args); 066 } 067 068 /** 069 * Constructor. 070 * @param cause The root exception. 071 * @param status The HTTP status code. 072 */ 073 public RestException(Throwable cause, int status) { 074 this(cause, status, null); 075 } 076 077 /** 078 * Constructor. 079 * 080 * @param status The HTTP status code. 081 * @param msg The status message. 082 * @param args Optional {@link MessageFormat}-style arguments. 083 */ 084 public RestException(int status, String msg, Object...args) { 085 this(null, status, msg, args); 086 } 087 088 /** 089 * Returns the root cause of this exception. 090 * 091 * <p> 092 * The root cause is the first exception in the init-cause parent chain that's not one of the following: 093 * <ul> 094 * <li>{@link RestException} 095 * <li>{@link InvocationTargetException} 096 * </ul> 097 * 098 * @return The root cause of this exception, or <jk>null</jk> if no root cause was found. 099 */ 100 public Throwable getRootCause() { 101 Throwable t = this; 102 while(t != null) { 103 t = t.getCause(); 104 if (! (t instanceof RestException || t instanceof InvocationTargetException)) 105 return t; 106 } 107 return null; 108 } 109 110 /** 111 * Returns all error messages from all errors in this stack. 112 * 113 * <p> 114 * Typically useful if you want to render all the error messages in the stack, but don't want to render all the 115 * stack traces too. 116 * 117 * @param scrubForXssVulnerabilities 118 * If <jk>true</jk>, replaces <js>'<'</js>, <js>'>'</js>, and <js>'&'</js> characters with spaces. 119 * @return All error messages from all errors in this stack. 120 */ 121 public String getFullStackMessage(boolean scrubForXssVulnerabilities) { 122 String msg = getMessage(); 123 StringBuilder sb = new StringBuilder(); 124 if (msg != null) { 125 if (scrubForXssVulnerabilities) 126 msg = msg.replace('<', ' ').replace('>', ' ').replace('&', ' '); 127 sb.append(msg); 128 } 129 Throwable e = getCause(); 130 while (e != null) { 131 msg = e.getMessage(); 132 if (msg != null && scrubForXssVulnerabilities) 133 msg = msg.replace('<', ' ').replace('>', ' ').replace('&', ' '); 134 String cls = e.getClass().getSimpleName(); 135 if (msg == null) 136 sb.append(format("\nCaused by ({0})", cls)); 137 else 138 sb.append(format("\nCaused by ({0}): {1}", cls, msg)); 139 e = e.getCause(); 140 } 141 return sb.toString(); 142 } 143 144 @Override /* Object */ 145 public int hashCode() { 146 int i = 0; 147 Throwable t = this; 148 while (t != null) { 149 for (StackTraceElement e : t.getStackTrace()) 150 i ^= e.hashCode(); 151 t = t.getCause(); 152 } 153 return i; 154 } 155 156 /** 157 * Set the occurrence count on this exception. 158 * 159 * @param occurrence The number of times this exception has occurred. 160 * @return This object (for method chaining). 161 * @deprecated Not used by new logging API. 162 */ 163 @Deprecated 164 protected RestException setOccurrence(int occurrence) { 165 this.occurrence = occurrence; 166 return this; 167 } 168 169 /** 170 * Set the status code on this exception. 171 * 172 * @param status The status code. 173 * @return This object (for method chaining). 174 */ 175 protected RestException setStatus(int status) { 176 this.status = status; 177 return this; 178 } 179 180 /** 181 * Returns the number of times this exception occurred on this servlet. 182 * 183 * @return 184 * The occurrence number if {@link RestResource#useStackTraceHashes() @RestResource(useStackTraceHashes)} is enabled, or <c>0</c> otherwise. 185 * @deprecated Not used by new logging API. 186 */ 187 @Deprecated 188 public int getOccurrence() { 189 return occurrence; 190 } 191 192 /** 193 * Returns the HTTP status code. 194 * 195 * @return The HTTP status code. 196 */ 197 public int getStatus() { 198 return status; 199 } 200 201 // When serialized, just serialize the message itself. 202 @Override /* Object */ 203 public String toString() { 204 return emptyIfNull(getLocalizedMessage()); 205 } 206}