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.client; 014 015import static java.lang.String.*; 016import static org.apache.juneau.internal.StringUtils.*; 017import static org.apache.juneau.internal.IOUtils.*; 018import static org.apache.juneau.internal.StringUtils.format; 019 020import java.io.*; 021import java.net.*; 022import java.text.*; 023import java.util.regex.*; 024 025import org.apache.http.*; 026import org.apache.http.client.*; 027import org.apache.http.util.*; 028import org.apache.juneau.reflect.*; 029 030/** 031 * Exception representing a <c>400+</c> HTTP response code against a remote resource. 032 * 033 * @deprecated Use {@link org.apache.juneau.rest.client2.RestCallException} class. 034 */ 035@Deprecated 036public final class RestCallException extends IOException { 037 038 private static final long serialVersionUID = 1L; 039 040 private int responseCode; 041 private String response, responseStatusMessage; 042 HttpResponseException e; 043 private HttpResponse httpResponse; 044 045 @SuppressWarnings("unused") 046 private String serverExceptionName, serverExceptionMessage, serverExceptionTrace; 047 048 /** 049 * Constructor. 050 * 051 * @param message The {@link MessageFormat}-style message. 052 * @param args Optional {@link MessageFormat}-style arguments. 053 */ 054 public RestCallException(String message, Object...args) { 055 super(format(message, args)); 056 } 057 058 /** 059 * Constructor. 060 * 061 * @param cause The cause of this exception. 062 * @param message The {@link MessageFormat}-style message. 063 * @param args Optional {@link MessageFormat}-style arguments. 064 */ 065 public RestCallException(Throwable cause, String message, Object...args) { 066 this(getMessage(cause, message, null), args); 067 initCause(cause); 068 } 069 070 /** 071 * Constructor. 072 * 073 * @param e The inner cause of the exception. 074 */ 075 public RestCallException(Exception e) { 076 super(e.getLocalizedMessage(), e); 077 if (e instanceof FileNotFoundException) { 078 responseCode = 404; 079 } else if (e.getMessage() != null) { 080 Pattern p = Pattern.compile("[^\\d](\\d{3})[^\\d]"); 081 Matcher m = p.matcher(e.getMessage()); 082 if (m.find()) 083 responseCode = Integer.parseInt(m.group(1)); 084 } 085 setStackTrace(e.getStackTrace()); 086 } 087 088 /** 089 * Create an exception with a simple message and the status code and body of the specified response. 090 * 091 * @param msg The exception message. 092 * @param response The HTTP response object. 093 * @throws IOException Thrown by underlying stream. 094 */ 095 public RestCallException(String msg, HttpResponse response) throws IOException { 096 super(format("{0}\n{1}\nstatus=''{2}''\nResponse: \n{3}", msg, response.getStatusLine().getStatusCode(), EntityUtils.toString(response.getEntity(), UTF8))); 097 } 098 099 /** 100 * Constructor. 101 * 102 * @param responseCode The response code. 103 * @param responseMsg The response message. 104 * @param method The HTTP method (for message purposes). 105 * @param url The HTTP URL (for message purposes). 106 * @param response The response from the server. 107 */ 108 public RestCallException(int responseCode, String responseMsg, String method, URI url, String response) { 109 super(format("HTTP method ''{0}'' call to ''{1}'' caused response code ''{2}, {3}''.\nResponse: \n{4}", method, url, responseCode, responseMsg, response)); 110 this.responseCode = responseCode; 111 this.responseStatusMessage = responseMsg; 112 this.response = response; 113 } 114 115 /** 116 * Sets the server-side exception details. 117 * 118 * @param exceptionName The <c>Exception-Name:</c> header specifying the full name of the exception. 119 * @param exceptionMessage 120 * The <c>Exception-Message:</c> header specifying the message returned by {@link Throwable#getMessage()}. 121 * @param exceptionTrace The stack trace of the exception returned by {@link Throwable#printStackTrace()}. 122 * @return This object (for method chaining). 123 */ 124 protected RestCallException setServerException(Header exceptionName, Header exceptionMessage, Header exceptionTrace) { 125 if (exceptionName != null) 126 serverExceptionName = exceptionName.getValue(); 127 if (exceptionMessage != null) 128 serverExceptionMessage = exceptionMessage.getValue(); 129 if (exceptionTrace != null) 130 serverExceptionTrace = exceptionTrace.getValue(); 131 return this; 132 } 133 134 /** 135 * Tries to reconstruct and re-throw the server-side exception. 136 * 137 * <p> 138 * The exception is based on the following HTTP response headers: 139 * <ul> 140 * <li><c>Exception-Name:</c> - The full class name of the exception. 141 * <li><c>Exception-Message:</c> - The message returned by {@link Throwable#getMessage()}. 142 * <li><c>Exception-Trace:</c> - The stack trace of the exception returned by {@link Throwable#printStackTrace()}. 143 * </ul> 144 * 145 * <p> 146 * Does nothing if the server-side exception could not be reconstructed. 147 * 148 * <p> 149 * Currently only supports <c>Throwables</c> with either a public no-arg constructor 150 * or a public constructor that takes in a simple string message. 151 * 152 * @param cl The classloader to use to resolve the throwable class name. 153 * @param throwables The possible throwables. 154 * @throws Throwable If the throwable could be reconstructed. 155 */ 156 protected void throwServerException(ClassLoader cl, Class<?>...throwables) throws Throwable { 157 if (serverExceptionName != null) { 158 for (Class<?> t : throwables) 159 if (t.getName().endsWith(serverExceptionName)) 160 doThrow(t, serverExceptionMessage); 161 try { 162 ClassInfo t = ClassInfo.of(cl.loadClass(serverExceptionName)); 163 if (t.isChildOf(RuntimeException.class) || t.isChildOf(Error.class)) 164 doThrow(t.inner(), serverExceptionMessage); 165 } catch (ClassNotFoundException e2) { /* Ignore */ } 166 } 167 } 168 169 private void doThrow(Class<?> t, String msg) throws Throwable { 170 ConstructorInfo c = null; 171 ClassInfo ci = ClassInfo.of(t); 172 if (msg != null) { 173 c = ci.getPublicConstructor(String.class); 174 if (c != null) 175 throw c.<Throwable>invoke(msg); 176 c = ci.getPublicConstructor(Object.class); 177 if (c != null) 178 throw c.<Throwable>invoke(msg); 179 } 180 c = ci.getPublicConstructor(); 181 if (c != null) 182 throw c.<Throwable>invoke(); 183 } 184 185 /** 186 * Sets the HTTP response object that caused this exception. 187 * 188 * @param httpResponse The HTTP response object. 189 * @return This object (for method chaining). 190 */ 191 protected RestCallException setHttpResponse(HttpResponse httpResponse) { 192 this.httpResponse = httpResponse; 193 return this; 194 } 195 196 /** 197 * Returns the HTTP response object that caused this exception. 198 * 199 * @return 200 * The HTTP response object that caused this exception, or <jk>null</jk> if no response was created yet when the 201 * exception was thrown. 202 */ 203 public HttpResponse getHttpResponse() { 204 return this.httpResponse; 205 } 206 207 /** 208 * Returns the HTTP response status code. 209 * 210 * @return The response status code. If a connection could not be made at all, returns <c>0</c>. 211 */ 212 public int getResponseCode() { 213 return responseCode; 214 } 215 216 /** 217 * Returns the HTTP response message body text. 218 * 219 * @return The response message body text. 220 */ 221 public String getResponseMessage() { 222 return response; 223 } 224 225 /** 226 * Returns the response status message as a plain string. 227 * 228 * @return The response status message. 229 */ 230 public String getResponseStatusMessage() { 231 return responseStatusMessage; 232 } 233 234 /** 235 * Finds the message. 236 * 237 * @param cause The cause. 238 * @param msg The message. 239 * @param def The default value if both above are <jk>null</jk>. 240 * @return The resolved message. 241 */ 242 protected static final String getMessage(Throwable cause, String msg, String def) { 243 if (msg != null) 244 return msg; 245 if (cause != null) 246 return cause.getMessage(); 247 return def; 248 } 249}