Search in sources :

Example 1 with RestFailure

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();
}
Also used : RestFailure(com.peterphi.std.guice.restclient.jaxb.RestFailure) StreamSource(javax.xml.transform.stream.StreamSource) StringReader(java.io.StringReader) JAXBContext(javax.xml.bind.JAXBContext)

Example 2 with RestFailure

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);
        }
    }
}
Also used : JAXBUnmarshalException(org.jboss.resteasy.plugins.providers.jaxb.JAXBUnmarshalException) RestFailure(com.peterphi.std.guice.restclient.jaxb.RestFailure) InputStream(java.io.InputStream) RestException(com.peterphi.std.guice.restclient.exception.RestException) ResponseProcessingException(javax.ws.rs.client.ResponseProcessingException) ExceptionInfo(com.peterphi.std.guice.restclient.jaxb.ExceptionInfo)

Example 3 with RestFailure

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);
    }
}
Also used : UnhandledException(org.jboss.resteasy.spi.UnhandledException) RestFailure(com.peterphi.std.guice.restclient.jaxb.RestFailure) TwitterBootstrapRestFailurePageRenderer(com.peterphi.std.guice.web.rest.pagewriter.TwitterBootstrapRestFailurePageRenderer) RestFailureMarshaller(com.peterphi.std.guice.web.rest.jaxrs.exception.RestFailureMarshaller)

Example 4 with RestFailure

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;
}
Also used : ClientResponse(org.jboss.resteasy.client.jaxrs.internal.ClientResponse) Response(javax.ws.rs.core.Response) ClientResponse(org.jboss.resteasy.client.jaxrs.internal.ClientResponse) RestFailure(com.peterphi.std.guice.restclient.jaxb.RestFailure) WebApplicationException(javax.ws.rs.WebApplicationException) WebApplicationException(javax.ws.rs.WebApplicationException) ApplicationException(org.jboss.resteasy.spi.ApplicationException)

Example 5 with RestFailure

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;
}
Also used : ApplicationException(org.jboss.resteasy.spi.ApplicationException) RestFailure(com.peterphi.std.guice.restclient.jaxb.RestFailure) RestException(com.peterphi.std.guice.restclient.exception.RestException) Date(java.util.Date)

Aggregations

RestFailure (com.peterphi.std.guice.restclient.jaxb.RestFailure)6 RestException (com.peterphi.std.guice.restclient.exception.RestException)2 JAXBContext (javax.xml.bind.JAXBContext)2 StreamSource (javax.xml.transform.stream.StreamSource)2 ApplicationException (org.jboss.resteasy.spi.ApplicationException)2 ExceptionInfo (com.peterphi.std.guice.restclient.jaxb.ExceptionInfo)1 RestFailureMarshaller (com.peterphi.std.guice.web.rest.jaxrs.exception.RestFailureMarshaller)1 TwitterBootstrapRestFailurePageRenderer (com.peterphi.std.guice.web.rest.pagewriter.TwitterBootstrapRestFailurePageRenderer)1 InputStream (java.io.InputStream)1 StringReader (java.io.StringReader)1 Date (java.util.Date)1 WebApplicationException (javax.ws.rs.WebApplicationException)1 ResponseProcessingException (javax.ws.rs.client.ResponseProcessingException)1 Response (javax.ws.rs.core.Response)1 ClientResponse (org.jboss.resteasy.client.jaxrs.internal.ClientResponse)1 JAXBUnmarshalException (org.jboss.resteasy.plugins.providers.jaxb.JAXBUnmarshalException)1 UnhandledException (org.jboss.resteasy.spi.UnhandledException)1