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 * <div class='warn'> 027 * <b>Deprecated</b> - Use {@link HttpException} 028 * </div> 029 * 030 * <p> 031 * REST methods on subclasses of {@link RestServlet} can throw this exception to trigger an HTTP status other than the 032 * automatically-generated <c>404</c>, <c>405</c>, and <c>500</c> statuses. 033 */ 034@Deprecated 035public class RestException extends RuntimeException { 036 037 private static final long serialVersionUID = 1L; 038 039 private int status; 040 @Deprecated private int occurrence; 041 042 /** 043 * Constructor. 044 * 045 * @param cause The cause of this exception. 046 * @param status The HTTP status code. 047 * @param msg The status message. 048 * @param args Optional {@link MessageFormat}-style arguments. 049 */ 050 public RestException(Throwable cause, int status, String msg, Object...args) { 051 super(message(cause, msg, args), cause); 052 this.status = status; 053 } 054 055 /** 056 * Constructor. 057 * 058 * @param msg The status message. 059 */ 060 public RestException(String msg) { 061 super(msg, null); 062 } 063 064 private static String message(Throwable cause, String msg, Object...args) { 065 if (msg == null && cause != null) 066 return firstNonEmpty(cause.getLocalizedMessage(), cause.getClass().getName()); 067 return format(msg, args); 068 } 069 070 /** 071 * Constructor. 072 * @param cause The root exception. 073 * @param status The HTTP status code. 074 */ 075 public RestException(Throwable cause, int status) { 076 this(cause, status, null); 077 } 078 079 /** 080 * Constructor. 081 * 082 * @param status The HTTP status code. 083 * @param msg The status message. 084 * @param args Optional {@link MessageFormat}-style arguments. 085 */ 086 public RestException(int status, String msg, Object...args) { 087 this(null, status, msg, args); 088 } 089 090 /** 091 * Returns the root cause of this exception. 092 * 093 * <p> 094 * The root cause is the first exception in the init-cause parent chain that's not one of the following: 095 * <ul> 096 * <li>{@link RestException} 097 * <li>{@link InvocationTargetException} 098 * </ul> 099 * 100 * @return The root cause of this exception, or <jk>null</jk> if no root cause was found. 101 */ 102 public Throwable getRootCause() { 103 Throwable t = this; 104 while(t != null) { 105 t = t.getCause(); 106 if (! (t instanceof RestException || t instanceof InvocationTargetException)) 107 return t; 108 } 109 return null; 110 } 111 112 /** 113 * Returns all error messages from all errors in this stack. 114 * 115 * <p> 116 * Typically useful if you want to render all the error messages in the stack, but don't want to render all the 117 * stack traces too. 118 * 119 * @param scrubForXssVulnerabilities 120 * If <jk>true</jk>, replaces <js>'<'</js>, <js>'>'</js>, and <js>'&'</js> characters with spaces. 121 * @return All error messages from all errors in this stack. 122 */ 123 public String getFullStackMessage(boolean scrubForXssVulnerabilities) { 124 String msg = getMessage(); 125 StringBuilder sb = new StringBuilder(); 126 if (msg != null) { 127 if (scrubForXssVulnerabilities) 128 msg = msg.replace('<', ' ').replace('>', ' ').replace('&', ' '); 129 sb.append(msg); 130 } 131 Throwable e = getCause(); 132 while (e != null) { 133 msg = e.getMessage(); 134 if (msg != null && scrubForXssVulnerabilities) 135 msg = msg.replace('<', ' ').replace('>', ' ').replace('&', ' '); 136 String cls = e.getClass().getSimpleName(); 137 if (msg == null) 138 sb.append(format("\nCaused by ({0})", cls)); 139 else 140 sb.append(format("\nCaused by ({0}): {1}", cls, msg)); 141 e = e.getCause(); 142 } 143 return sb.toString(); 144 } 145 146 @Override /* Object */ 147 public int hashCode() { 148 int i = 0; 149 Throwable t = this; 150 while (t != null) { 151 for (StackTraceElement e : t.getStackTrace()) 152 i ^= e.hashCode(); 153 t = t.getCause(); 154 } 155 return i; 156 } 157 158 /** 159 * Set the occurrence count on this exception. 160 * 161 * @param occurrence The number of times this exception has occurred. 162 * @return This object (for method chaining). 163 */ 164 @Deprecated 165 protected RestException setOccurrence(int occurrence) { 166 this.occurrence = occurrence; 167 return this; 168 } 169 170 /** 171 * Set the status code on this exception. 172 * 173 * @param status The status code. 174 * @return This object (for method chaining). 175 */ 176 protected RestException setStatus(int status) { 177 this.status = status; 178 return this; 179 } 180 181 /** 182 * Returns the number of times this exception occurred on this servlet. 183 * 184 * @return 185 * The occurrence number if {@link RestResource#useStackTraceHashes() @RestResource(useStackTraceHashes)} is enabled, or <c>0</c> otherwise. 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}