public Response toResponse()

in rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/DefaultExceptionMapper.java [81:196]


    public Response toResponse(Throwable throwable1) {
        String user = Strings.toString(Entitlements.getEntitlementContext());
        if (user==null) user = "<not_logged_in>";

        String path = null;
        try {
            // get path if possible for all requests
            ContainerRequestContext requestContext = resourceContext.getResource(ContainerRequestContext.class);
            path = requestContext.getUriInfo().getPath();
            if (LOG.isTraceEnabled()) {
                LOG.trace("ERROR CONTEXT DETAILS for "+throwable1);
                LOG.trace("url: "+requestContext.getUriInfo());
                LOG.trace("headers: "+requestContext.getHeaders());
            }
        } catch (Exception e) {
            Exceptions.propagateIfFatal(e);
            if (firstEncounter(e)) {
                // include debug trace for everything the first time we get one
                LOG.debug("Unable to resolve path on error "+throwable1+" (logging once): "+e);
            }
        }
        if (path==null) path = "<path_unavailable>";

        // EofException is thrown when the connection is reset,
        // for example when refreshing the browser window.
        // Don't depend on jetty, could be running in other environments as well.
        if (throwable1.getClass().getName().equals("org.eclipse.jetty.io.EofException")) {
            if (LOG.isTraceEnabled()) {
                LOG.trace("REST request {} running as user {} was disconnected, threw: {}",
                        path, user,
                        Exceptions.collapseText(throwable1));
            }
            return null;
        }

        String errorReference = Identifiers.makeRandomId(13);
        Throwable throwable2 = Exceptions.getFirstInteresting(throwable1);
        if (isSevere(throwable2)) {
            LOG.warn("REST request {} running as {} threw severe: {} (ref {})",
                    path, user,
                    Exceptions.collapseText(throwable1), errorReference);
        } else {
            LOG.debug("REST request {} running as {} threw: {} (ref {})",
                    path, user,
                    Exceptions.collapseText(throwable1), errorReference);
        }
        logExceptionDetailsForDebugging(throwable1, errorReference);

        // Some methods will throw this, which gets converted automatically
        if (throwable2 instanceof WebApplicationException) {
            if (throwable2 instanceof ApiError.WebApplicationExceptionWithApiError) {
                ApiError apiError = ((ApiError.WebApplicationExceptionWithApiError)throwable2).getApiError();
                if (!isTraceVisibleToUser()) {
                    if (apiError.getDetails() != null) {
                        LOG.debug("Details of suppressed API error ref " + errorReference + ": " + apiError.getDetails());
                    }
                    return ApiError.builder().message(apiError.getMessage()).details("Reference: " + errorReference).errorCode(apiError.getError()).build().asJsonResponse();
                } else {
                    // include error reference
                    return ApiError.builder().copy(apiError).message(""+apiError.getMessage()+" (Reference: "+errorReference+")").build().asJsonResponse();
                }
            } else {
                WebApplicationException wae = (WebApplicationException) throwable2;
                // could suppress all messages if anything includes unwanted details (but believed not to be the case)
                // note error reference not included, but we'll live with that for this error which isn't used (will still be logged above, just not reported to user)
                return wae.getResponse();
            }
        }

        // The nicest way for methods to provide errors, wrap as this, and the stack trace will be suppressed
        if (throwable2 instanceof UserFacingException) {
            return ApiError.of(throwable2.getMessage()).asBadRequestResponseJson();
        }

        // For everything else, a trace is supplied unless blocked
        
        // Assume ClassCoercionExceptions are caused by TypeCoercions from input parameters gone wrong
        // And IllegalArgumentException for malformed input parameters.
        if (throwable2 instanceof ClassCoercionException || throwable2 instanceof IllegalArgumentException) {
            if (!isTraceVisibleToUser()) {
                return ApiError.of(throwable2.getMessage()).asBadRequestResponseJson();
            }
            return ApiError.of(throwable2).asBadRequestResponseJson();
        }

        // YAML exception 
        if (throwable2 instanceof YAMLException) {
            return ApiError.builder().message(throwable2.getMessage()).details("Reference: "+errorReference).prefixMessage("Invalid YAML").build().asBadRequestResponseJson();
        }

        if (!isTooUninterestingToLogWarn(throwable2)) {
            if (encounteredUnknownExceptions.add( throwable2.getClass() )) {
                LOG.warn("REST call reference "+errorReference+" generated exception type "+throwable2.getClass()+" unrecognized in "+getClass()+" (subsequent occurrences will be logged debug only): " + throwable2, throwable2);
            }
        }

        // Before saying server error, look for a user-facing exception anywhere in the hierarchy
        UserFacingException userFacing = Exceptions.getFirstThrowableOfType(throwable1, UserFacingException.class);
        if (userFacing instanceof UserFacingException) {
            return ApiError.builder().message(userFacing.getMessage()).details("Reference: "+errorReference).build().asBadRequestResponseJson();
        }

        if (!isTraceVisibleToUser()) {
            return ApiError.builder()
                    .message("Internal error. Contact server administrator citing reference " + errorReference +" to consult logs for more details.")
                    .details("Reference: "+errorReference)
                    .build().asResponse(Status.INTERNAL_SERVER_ERROR, MediaType.APPLICATION_JSON_TYPE);
        } else {
            Builder rb = ApiError.builderFromThrowable(Exceptions.collapse(throwable2));
            if (Strings.isBlank(rb.getMessage())) {
                rb.message("Internal error. Contact server administrator citing reference " + errorReference + " to consult logs for more details.");
            }
            rb.details("Reference: "+errorReference);
            return rb.build().asResponse(Status.INTERNAL_SERVER_ERROR, MediaType.APPLICATION_JSON_TYPE);
        }
    }