org.apache.juneau.rest.client.RestCallException Maven / Gradle / Ivy
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
// * with the License. You may obtain a copy of the License at *
// * *
// * http://www.apache.org/licenses/LICENSE-2.0 *
// * *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
package org.apache.juneau.rest.client;
import static java.lang.String.*;
import static org.apache.juneau.internal.ClassUtils.*;
import static org.apache.juneau.internal.IOUtils.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.regex.*;
import org.apache.http.*;
import org.apache.http.client.*;
import org.apache.http.util.*;
/**
* Exception representing a 400+
HTTP response code against a remote resource.
*/
public final class RestCallException extends IOException {
private static final long serialVersionUID = 1L;
private int responseCode;
private String response, responseStatusMessage;
HttpResponseException e;
private HttpResponse httpResponse;
@SuppressWarnings("unused")
private String serverExceptionName, serverExceptionMessage, serverExceptionTrace;
/**
* Constructor.
*
* @param msg The exception message.
*/
public RestCallException(String msg) {
super(msg);
}
/**
* Constructor.
*
* @param e The inner cause of the exception.
*/
public RestCallException(Exception e) {
super(e.getLocalizedMessage(), e);
if (e instanceof FileNotFoundException) {
responseCode = 404;
} else if (e.getMessage() != null) {
Pattern p = Pattern.compile("[^\\d](\\d{3})[^\\d]");
Matcher m = p.matcher(e.getMessage());
if (m.find())
responseCode = Integer.parseInt(m.group(1));
}
setStackTrace(e.getStackTrace());
}
/**
* Create an exception with a simple message and the status code and body of the specified response.
*
* @param msg The exception message.
* @param response The HTTP response object.
* @throws ParseException
* @throws IOException
*/
public RestCallException(String msg, HttpResponse response) throws ParseException, IOException {
super(format("%s%nstatus='%s'%nResponse: %n%s%n", msg, response.getStatusLine().getStatusCode(), EntityUtils.toString(response.getEntity(), UTF8)));
}
/**
* Constructor.
*
* @param responseCode The response code.
* @param responseMsg The response message.
* @param method The HTTP method (for message purposes).
* @param url The HTTP URL (for message purposes).
* @param response The response from the server.
*/
public RestCallException(int responseCode, String responseMsg, String method, URI url, String response) {
super(format("HTTP method '%s' call to '%s' caused response code '%s,%s'.%nResponse: %n%s%n", method, url, responseCode, responseMsg, response));
this.responseCode = responseCode;
this.responseStatusMessage = responseMsg;
this.response = response;
}
/**
* Sets the server-side exception details.
*
* @param exceptionName The Exception-Name:
header specifying the full name of the exception.
* @param exceptionMessage
* The Exception-Message:
header specifying the message returned by {@link Throwable#getMessage()}.
* @param exceptionTrace The stack trace of the exception returned by {@link Throwable#printStackTrace()}.
* @return This object (for method chaining).
*/
protected RestCallException setServerException(Header exceptionName, Header exceptionMessage, Header exceptionTrace) {
if (exceptionName != null)
serverExceptionName = exceptionName.getValue();
if (exceptionMessage != null)
serverExceptionMessage = exceptionMessage.getValue();
if (exceptionTrace != null)
serverExceptionTrace = exceptionTrace.getValue();
return this;
}
/**
* Tries to reconstruct and re-throw the server-side exception.
*
*
* The exception is based on the following HTTP response headers:
*
* Exception-Name:
- The full class name of the exception.
* Exception-Message:
- The message returned by {@link Throwable#getMessage()}.
* Exception-Trace:
- The stack trace of the exception returned by {@link Throwable#printStackTrace()}.
*
*
*
* Does nothing if the server-side exception could not be reconstructed.
*
*
* Currently only supports Throwables
with either a public no-arg constructor
* or a public constructor that takes in a simple string message.
*
* @param cl The classloader to use to resolve the throwable class name.
* @throws Throwable If the throwable could be reconstructed.
*/
protected void throwServerException(ClassLoader cl) throws Throwable {
if (serverExceptionName != null) {
Throwable t = null;
try {
Class> exceptionClass = cl.loadClass(serverExceptionName);
Constructor> c = findPublicConstructor(exceptionClass, String.class);
if (c != null)
t = (Throwable)c.newInstance(serverExceptionMessage);
if (t == null) {
c = findPublicConstructor(exceptionClass);
if (c != null)
t = (Throwable)c.newInstance();
}
} catch (Exception e2) {
e2.printStackTrace();
}
if (t != null)
throw t;
}
}
/**
* Sets the HTTP response object that caused this exception.
*
* @param httpResponse The HTTP response object.
* @return This object (for method chaining).
*/
protected RestCallException setHttpResponse(HttpResponse httpResponse) {
this.httpResponse = httpResponse;
return this;
}
/**
* Returns the HTTP response object that caused this exception.
*
* @return
* The HTTP response object that caused this exception, or null if no response was created yet when the
* exception was thrown.
*/
public HttpResponse getHttpResponse() {
return this.httpResponse;
}
/**
* Returns the HTTP response status code.
*
* @return The response status code. If a connection could not be made at all, returns 0
.
*/
public int getResponseCode() {
return responseCode;
}
/**
* Returns the HTTP response message body text.
*
* @return The response message body text.
*/
public String getResponseMessage() {
return response;
}
/**
* Returns the response status message as a plain string.
*
* @return The response status message.
*/
public String getResponseStatusMessage() {
return responseStatusMessage;
}
/**
* Sets the inner cause for this exception.
*
* @param cause The inner cause.
* @return This object (for method chaining).
*/
@Override /* Throwable */
public synchronized RestCallException initCause(Throwable cause) {
super.initCause(cause);
return this;
}
}