aboutsummaryrefslogtreecommitdiffstats
path: root/jdisc_core/src/main/java/com/yahoo/jdisc/Response.java
blob: f9df919b44ef27196095ec871ce3b59912ce6b1d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jdisc;

import com.yahoo.jdisc.handler.ContentChannel;
import com.yahoo.jdisc.handler.RequestHandler;
import com.yahoo.jdisc.handler.ResponseDispatch;
import com.yahoo.jdisc.handler.ResponseHandler;

import java.util.HashMap;
import java.util.Map;

/**
 * <p>This class represents the single response (which may have any content model that a {@link RequestHandler} chooses
 * to implement) of some single request. Contrary to the {@link Request} class, this has no active reference to the
 * parent {@link Container} (this is tracked internally by counting the number of requests vs the number of responses
 * seen). The {@link ResponseHandler} of a Response is implicit in the invocation of {@link
 * RequestHandler#handleRequest(Request, ResponseHandler)}.</p>
 *
 * <p>The usage pattern of the Response is similar to that of the Request in that the {@link ResponseHandler} returns a
 * {@link ContentChannel} into which to write the Response content.</p>
 *
 * @author Simon Thoresen Hult
 * @see Request
 * @see ResponseHandler
 */
public class Response {

    /**
     * This interface acts as a namespace for the built-in status codes of the jDISC core. These are identical to the
     * common HTTP status codes (see <a href="http://www.rfc-editor.org/rfc/rfc2616.txt">RFC2616</a>).
     */
    public interface Status {

        /**
         * <p>1xx: Informational - Request received, continuing process.</p>
         */
        int CONTINUE = 100;
        int SWITCHING_PROTOCOLS = 101;
        int PROCESSING = 102;

        /**
         * <p>2xx: Success - The action was successfully received, understood, and accepted.</p>
         */
        int OK = 200;
        int CREATED = 201;
        int ACCEPTED = 202;
        int NON_AUTHORITATIVE_INFORMATION = 203;
        int NO_CONTENT = 204;
        int RESET_CONTENT = 205;
        int PARTIAL_CONTENT = 206;
        int MULTI_STATUS = 207;

        /**
         * <p>3xx: Redirection - Further action must be taken in order to complete the request.</p>
         */
        int MULTIPLE_CHOICES = 300;
        int MOVED_PERMANENTLY = 301;
        int FOUND = 302;
        int SEE_OTHER = 303;
        int NOT_MODIFIED = 304;
        int USE_PROXY = 305;
        int TEMPORARY_REDIRECT = 307;

        /**
         * <p>4xx: Client Error - The request contains bad syntax or cannot be fulfilled.</p>
         */
        int BAD_REQUEST = 400;
        int UNAUTHORIZED = 401;
        int PAYMENT_REQUIRED = 402;
        int FORBIDDEN = 403;
        int NOT_FOUND = 404;
        int METHOD_NOT_ALLOWED = 405;
        int NOT_ACCEPTABLE = 406;
        int PROXY_AUTHENTICATION_REQUIRED = 407;
        int REQUEST_TIMEOUT = 408;
        int CONFLICT = 409;
        int GONE = 410;
        int LENGTH_REQUIRED = 411;
        int PRECONDITION_FAILED = 412;
        int REQUEST_TOO_LONG = 413;
        int REQUEST_URI_TOO_LONG = 414;
        int UNSUPPORTED_MEDIA_TYPE = 415;
        int REQUESTED_RANGE_NOT_SATISFIABLE = 416;
        int EXPECTATION_FAILED = 417;
        int INSUFFICIENT_SPACE_ON_RESOURCE = 419;
        int METHOD_FAILURE = 420;
        int UNPROCESSABLE_ENTITY = 422;
        int LOCKED = 423;
        int FAILED_DEPENDENCY = 424;
        int TOO_MANY_REQUESTS = 429;

        /** 5xx: Server Error - The server failed to fulfill an apparently valid request. */
        int INTERNAL_SERVER_ERROR = 500;
        int NOT_IMPLEMENTED = 501;
        int BAD_GATEWAY = 502;
        int SERVICE_UNAVAILABLE = 503;
        int GATEWAY_TIMEOUT = 504;
        int VERSION_NOT_SUPPORTED = 505;
        int INSUFFICIENT_STORAGE = 507;
    }

    private final Map<String, Object> context = new HashMap<>();
    private final HeaderFields headers = new HeaderFields();
    private Throwable error;
    private int status;
    private Request.RequestType requestType;

    /**
     * Creates a new instance of this class.
     *
     * @param status The status code to assign to this.
     */
    public Response(int status) {
        this(status, null);
    }

    /**
     * Creates a new instance of this class.
     *
     * @param status The status code to assign to this.
     * @param error  The error to assign to this.
     */
    public Response(int status, Throwable error) {
        this.status = status;
        this.error = error;
    }

    /**
     * <p>Returns the named application context objects. This data is not intended for network transport, rather they
     * are intended for passing shared data between components of an Application.</p>
     *
     * <p>Modifying the context map is a thread-unsafe operation -- any changes made after calling {@link
     * ResponseHandler#handleResponse(Response)} might never become visible to other threads, and might throw
     * ConcurrentModificationExceptions in other threads.</p>
     *
     * @return The context map.
     */
    public Map<String, Object> context() {
        return context;
    }

    /**
     * <p>Returns the set of header fields of this Request. These are the meta-data of the Request, and are not applied
     * to any internal {@link Container} logic. Modifying headers is a thread-unsafe operation -- any changes made after
     * calling {@link ResponseHandler#handleResponse(Response)} might never become visible to other threads, and might
     * throw ConcurrentModificationExceptions in other threads.</p>
     *
     * @return The header fields.
     */
    public HeaderFields headers() {
        return headers;
    }

    /**
     * <p>Returns the status code of this response. This is an integer result code of the attempt to understand and
     * satisfy the corresponding {@link Request}. It is encouraged, although not enforced, to use the built-in {@link
     * Status} codes whenever possible.</p>
     *
     * @return The status code.
     * @see #setStatus(int)
     */
    public int getStatus() {
        return status;
    }

    /**
     * <p>Sets the status code of this response. This is an integer result code of the attempt to understand and
     * satisfy the corresponding {@link Request}. It is encouraged, although not enforced, to use the built-in {@link
     * Status} codes whenever possible. </p>
     *
     * <p>Because access to this field is not guarded by any lock, any changes made after calling {@link
     * ResponseHandler#handleResponse(Response)} might never become visible to other threads.</p>
     *
     * @param status The status code to set.
     * @return This, to allow chaining.
     * @see #getStatus()
     */
    public Response setStatus(int status) {
        this.status = status;
        return this;
    }

    /**
     * <p>Returns the error of this response, or null if none has been set. This is typically non-null if the status
     * indicates an unsuccessful response.</p>
     *
     * @return The error.
     * @see #getError()
     */
    public Throwable getError() {
        return error;
    }

    /**
     * <p>Sets the error of this response. It is encouraged, although not enforced, to use this field to attach
     * additional information to an unsuccessful response.</p>
     *
     * <p>Because access to this field is not guarded by any lock, any changes made after calling {@link
     * ResponseHandler#handleResponse(Response)} might never become visible to other threads.</p>
     *
     * @param error The error to set.
     * @return This, to allow chaining.
     * @see #getError()
     */
    public Response setError(Throwable error) {
        this.error = error;
        return this;
    }

    /** Sets the type classification of this request for metric collection purposes */
    public void setRequestType(Request.RequestType requestType) {
        this.requestType = requestType;
    }

    /** Returns the type classification of this request for metric collection purposes, or null if not set */
    public Request.RequestType getRequestType() { return requestType; }

    /**
     * This is a convenience method for creating a Response with status {@link Status#GATEWAY_TIMEOUT} and passing
     * that to the given {@link ResponseHandler#handleResponse(Response)}. For trivial implementations of {@link
     * RequestHandler#handleTimeout(Request, ResponseHandler)}, simply call this method.
     *
     * @param handler The handler to pass the timeout {@link Response} to.
     */
    public static void dispatchTimeout(ResponseHandler handler) {
        ResponseDispatch.newInstance(Status.GATEWAY_TIMEOUT).dispatch(handler);
    }

}