001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2014-2015 ForgeRock AS.
015 */
016package org.forgerock.http.protocol;
017
018/**
019 * An HTTP Framework Exception that can be used by filters/handlers to simplify
020 * control-flow inside async call-backs.
021 * <p>
022 * As a developer, it's still useful to be able to use try-catch blocks, even if the catch block converts
023 * the {@link ResponseException} to a {@code Promise<Response, ...>}.
024 * <p>
025 * Note that this is a convenience class offered by the HTTP Framework, there is no requirement to use it in Filter
026 * or Handler implementations:
027 * <ul>
028 *     <li>Ease control-flow inside async call-backs or in synchronous code</li>
029 *     <li>Contains a {@link Response} that may be used to forward an error message without losing detailed
030 *     information about the cause of the failure</li>
031 *     <li>Contained {@link Response} may be automatically associated to this exception in order to keep track of the
032 *     original failure</li>
033 * </ul>
034 * @see Response#getCause()
035 */
036public class ResponseException extends Exception {
037    private static final long serialVersionUID = 7012424171155584261L;
038
039    private final Response response;
040
041    /**
042     * Constructs a ResponseException using the given {@code message}.
043     *
044     * @param message Error message
045     */
046    public ResponseException(String message) {
047        this(message, null);
048    }
049
050    /**
051     * Constructs a ResponseException using the given {@code response}.
052     * The provided Response won't be linked to this exception.
053     *
054     * @param response Response
055     * @see Response#setCause(Exception)
056     * @see #getResponse()
057     */
058    public ResponseException(Response response) {
059        this(response, null, null);
060    }
061
062    /**
063     * Constructs a ResponseException using the given {@code message} and parent {@code cause}.
064     * This constructor also build a {@link Response} object that will be linked to this exception instance.
065     *
066     * @param message Error message
067     * @param cause Error cause
068     */
069    public ResponseException(String message, Throwable cause) {
070        this(new Response(Status.INTERNAL_SERVER_ERROR).setEntity(message),
071             message,
072             cause,
073             true);
074    }
075
076    /**
077     * Constructs a ResponseException using the given {@code response}, {@code message} and parent {@code cause}.
078     * The provided Response won't be linked to this exception.
079     *
080     * @param response response object
081     * @param message Error message
082     * @param cause Error cause
083     */
084    public ResponseException(Response response, String message, Throwable cause) {
085        this(response, message, cause, false);
086    }
087
088    /**
089     * Constructs a ResponseException using the given {@code response}, {@code message} and parent {@code cause}, then
090     * link (if {@code link} is {@code true}) the given {@code response} to this exception.
091     *
092     * @param response response object
093     * @param message Error message
094     * @param cause Error cause
095     * @param link link this exception with the contained response
096     */
097    private ResponseException(Response response, String message, Throwable cause, boolean link) {
098        super(message, cause);
099        this.response = response;
100        if (link) {
101            // Auto-link the response with this exception instance
102            response.setCause(this);
103        }
104    }
105
106    /**
107     * Returns the response associated to this exception.
108     * It is intended to be used when propagating a specific Response message (constructed at the point where the
109     * original error occurred) in try-catch blocks:
110     *
111     * <pre>
112     *     {@code try {
113     *         doSomeStuff(request);
114     *       } catch (ResponseException e) {
115     *         return Promises.newResultPromise(e.getResponse());
116     *       }}
117     * </pre>
118     *
119     * <p>
120     * It can also be used as an informal pointer to the message that caused the exception (Client API usage)
121     *
122     * @return the response linked to this exception.
123     */
124    public Response getResponse() {
125        return response;
126    }
127}