use of com.peterphi.std.guice.restclient.jaxb.RestFailure in project stdlib by petergeneric.
the class RemoteExceptionClientResponseFilter method parseLegacyResponse.
/**
* This implementation is quite ugly (in particular the fact that XML is being processed as a string!) but it's only required
* very short-term as a patch to ease communication with services that are being migrated from the legacy mediasmiths
* codebase
* to the open source stdlib
*
* @param stream
*
* @return
*
* @throws IOException
*/
private RestFailure parseLegacyResponse(InputStream stream) throws IOException, JAXBException {
stream.reset();
final String xmlAsString = FileHelper.cat(stream);
final String modifiedXml = xmlAsString.replace("http://ns.mediasmithsforge.com/stdlib/rest/exception", "http://ns.peterphi.com/stdlib/rest/exception");
final JAXBContext ctx = jaxbContextResolver.getContext(RestFailure.class);
final JAXBElement<RestFailure> el = ctx.createUnmarshaller().unmarshal(new StreamSource(new StringReader(modifiedXml)), RestFailure.class);
return el.getValue();
}
use of com.peterphi.std.guice.restclient.jaxb.RestFailure in project stdlib by petergeneric.
the class RemoteExceptionClientResponseFilter method filter.
@Override
public void filter(final ClientRequestContext requestContext, final ClientResponseContext responseContext) throws IOException {
final int code = responseContext.getStatus();
String operationId;
if (Tracing.isVerbose()) {
operationId = requestContext.getHeaderString(TracingConstants.HTTP_HEADER_CORRELATION_ID);
if (operationId != null)
Tracing.logOngoing(operationId, "HTTP:resp", () -> "" + code);
else
// can't find outgoing trace id
operationId = Tracing.log("HTTP:resp:unexpected", () -> "" + code);
} else {
operationId = null;
}
if (code >= 200 && code <= 299)
// Do not run if the return code is 2xx
return;
if (responseContext.getHeaders().containsKey(RestThrowableConstants.HEADER_RICH_EXCEPTION)) {
try {
final InputStream is = responseContext.getEntityStream();
RestFailure failure;
if (tryParseLegacyExceptionNamespace) {
// If parsing the legacy namespace fails, throw the original parse error back to the client
try {
// Mark the start of the stream so we can reset back to it if we need to process this as a legacy exception
is.mark(Integer.MAX_VALUE);
failure = parseResponse(is);
} catch (JAXBUnmarshalException e) {
log.trace("Error parsing rich exception response, will fall back on parsing it as a legacy exception XML", e);
try {
failure = parseLegacyResponse(is);
} catch (Throwable legacyFailure) {
log.trace("Error parsing rich exception response as legacy rich exception XML!", legacyFailure);
// throw the original exception
throw e;
}
}
} else {
failure = parseResponse(is);
}
if (Tracing.isVerbose() && failure != null && failure.exception != null) {
final ExceptionInfo ei = failure.exception;
Tracing.logOngoing(operationId, "HTTP:error", () -> ei.shortName + " " + ei.detail);
}
RestException exception = exceptionFactory.build(failure, responseContext);
// Try to shorten the stack trace
exception.fillInStackTrace();
throw exception;
} catch (ResponseProcessingException e) {
throw e;
} catch (Throwable e) {
throw new ResponseProcessingException(null, "Error mapping exception from thrown from " + requestContext.getUri() + " to exception!", e);
}
}
}
use of com.peterphi.std.guice.restclient.jaxb.RestFailure in project stdlib by petergeneric.
the class GuicedResteasy method tryHandleException.
/**
* @param ctx
* @param response
* @param t
*
* @throws ServletException
* @throws IOException
* @throws RuntimeException
* @throws Error
*/
private void tryHandleException(HttpCallContext ctx, HttpServletResponse response, Throwable t) throws ServletException, IOException, RuntimeException, Error {
if (suppressClientAbortExceptions && t instanceof UnhandledException && t.getCause() != null) {
// Only look 20 exceptions deep
int maxDepth = 20;
Throwable cause = t.getCause();
while (cause != null && --maxDepth > 0) {
if (cause.getClass().getName().equals("org.apache.catalina.connector.ClientAbortException")) {
ignoredAborts.mark();
if (log.isTraceEnabled())
log.trace("Client aborted during request. Ignoring. Detail: " + ctx.getRequestInfo(), t);
return;
} else {
cause = cause.getCause();
}
}
}
log.warn("Failure during " + ctx.getRequestInfo(), t);
// If the response is already committed we can't render the exception elegantly
if (response.isCommitted())
rethrow(t);
try {
RestFailureMarshaller marshaller = new RestFailureMarshaller();
RestFailure failure = marshaller.renderFailure(t);
TwitterBootstrapRestFailurePageRenderer renderer = new TwitterBootstrapRestFailurePageRenderer(failure);
// internal error
response.setStatus(500);
// Render the HTML
final StringBuilder sb = new StringBuilder(4096);
renderer.writeHTML(sb);
response.getWriter().print(sb);
} catch (Throwable newException) {
log.warn("Error trying to present exception elegantly: ", newException);
// Rethrow the original exception, it's not our problem anymore
rethrow(t);
}
}
use of com.peterphi.std.guice.restclient.jaxb.RestFailure in project stdlib by petergeneric.
the class JAXRSExceptionMapper method getResponse.
public Response getResponse(Throwable exception) {
// Response will result in the code to render the Response hanging.
if (exception instanceof WebApplicationException) {
final WebApplicationException webappException = (WebApplicationException) exception;
// Ignore null responses or exceptions whose Response object is actually a client response (a failure in a remote service call)
if (webappException.getResponse() != null && !(webappException.getResponse() instanceof ClientResponse)) {
return webappException.getResponse();
}
}
// Represent the exception as a RestFailure object
final RestFailure failure = marshaller.renderFailure(exception);
// Log the failure
log.error(failure.id + " " + HttpCallContext.get().getRequestInfo() + " threw exception:", exception);
Response response = null;
// Try to use the custom renderer (if present)
if (renderer != null) {
try {
response = renderer.render(failure);
} catch (Exception e) {
log.warn("Exception rendering RestFailure", e);
}
}
// Give the HTML render an opportunity to run
if (response == null)
response = htmlRenderer.render(failure);
// Use the XML renderer if no other renderer has wanted to build the response
if (response == null)
// Fall back on the XML renderer
return xmlRenderer.render(failure);
else
return response;
}
use of com.peterphi.std.guice.restclient.jaxb.RestFailure in project stdlib by petergeneric.
the class RestFailureMarshaller method renderFailure.
/**
* Render a Throwable as a RestFailure
*
* @param e
*
* @return
*/
public RestFailure renderFailure(Throwable e) {
// Strip away ApplicationException wrappers
if (e.getCause() != null && (e instanceof ApplicationException)) {
return renderFailure(e.getCause());
}
RestFailure failure = new RestFailure();
failure.id = getOrGenerateFailureId();
failure.date = new Date();
if (e instanceof RestException) {
RestException re = (RestException) e;
failure.httpCode = re.getHttpCode();
failure.exception = renderThrowable(e);
} else {
// by default
failure.httpCode = 500;
failure.exception = renderThrowable(e);
}
return failure;
}
Aggregations