001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.message;
029
030import java.util.Locale;
031
032import org.apache.http.HttpEntity;
033import org.apache.http.HttpResponse;
034import org.apache.http.HttpVersion;
035import org.apache.http.ProtocolVersion;
036import org.apache.http.ReasonPhraseCatalog;
037import org.apache.http.StatusLine;
038import org.apache.http.util.Args;
039
040/**
041 * Basic implementation of {@link HttpResponse}.
042 *
043 * @see org.apache.http.impl.DefaultHttpResponseFactory
044 *
045 * @since 4.0
046 */
047public class BasicHttpResponse extends AbstractHttpMessage implements HttpResponse {
048
049    private StatusLine          statusline;
050    private ProtocolVersion     ver;
051    private int                 code;
052    private String              reasonPhrase;
053    private HttpEntity          entity;
054    private final ReasonPhraseCatalog reasonCatalog;
055    private Locale              locale;
056
057    /**
058     * Creates a new response.
059     * This is the constructor to which all others map.
060     *
061     * @param statusline        the status line
062     * @param catalog           the reason phrase catalog, or
063     *                          {@code null} to disable automatic
064     *                          reason phrase lookup
065     * @param locale            the locale for looking up reason phrases, or
066     *                          {@code null} for the system locale
067     */
068    public BasicHttpResponse(final StatusLine statusline,
069                             final ReasonPhraseCatalog catalog,
070                             final Locale locale) {
071        super();
072        this.statusline = Args.notNull(statusline, "Status line");
073        this.ver = statusline.getProtocolVersion();
074        this.code = statusline.getStatusCode();
075        this.reasonPhrase = statusline.getReasonPhrase();
076        this.reasonCatalog = catalog;
077        this.locale = locale;
078    }
079
080    /**
081     * Creates a response from a status line.
082     * The response will not have a reason phrase catalog and
083     * use the system default locale.
084     *
085     * @param statusline        the status line
086     */
087    public BasicHttpResponse(final StatusLine statusline) {
088        super();
089        this.statusline = Args.notNull(statusline, "Status line");
090        this.ver = statusline.getProtocolVersion();
091        this.code = statusline.getStatusCode();
092        this.reasonPhrase = statusline.getReasonPhrase();
093        this.reasonCatalog = null;
094        this.locale = null;
095    }
096
097    /**
098     * Creates a response from elements of a status line.
099     * The response will not have a reason phrase catalog and
100     * use the system default locale.
101     *
102     * @param ver       the protocol version of the response
103     * @param code      the status code of the response
104     * @param reason    the reason phrase to the status code, or
105     *                  {@code null}
106     */
107    public BasicHttpResponse(final ProtocolVersion ver,
108                             final int code,
109                             final String reason) {
110        super();
111        Args.notNegative(code, "Status code");
112        this.statusline = null;
113        this.ver = ver;
114        this.code = code;
115        this.reasonPhrase = reason;
116        this.reasonCatalog = null;
117        this.locale = null;
118    }
119
120
121    // non-javadoc, see interface HttpMessage
122    @Override
123    public ProtocolVersion getProtocolVersion() {
124        return this.ver;
125    }
126
127    // non-javadoc, see interface HttpResponse
128    @Override
129    public StatusLine getStatusLine() {
130        if (this.statusline == null) {
131            this.statusline = new BasicStatusLine(
132                    this.ver != null ? this.ver : HttpVersion.HTTP_1_1,
133                    this.code,
134                    this.reasonPhrase != null ? this.reasonPhrase : getReason(this.code));
135        }
136        return this.statusline;
137    }
138
139    // non-javadoc, see interface HttpResponse
140    @Override
141    public HttpEntity getEntity() {
142        return this.entity;
143    }
144
145    @Override
146    public Locale getLocale() {
147        return this.locale;
148    }
149
150    // non-javadoc, see interface HttpResponse
151    @Override
152    public void setStatusLine(final StatusLine statusline) {
153        this.statusline = Args.notNull(statusline, "Status line");
154        this.ver = statusline.getProtocolVersion();
155        this.code = statusline.getStatusCode();
156        this.reasonPhrase = statusline.getReasonPhrase();
157    }
158
159    // non-javadoc, see interface HttpResponse
160    @Override
161    public void setStatusLine(final ProtocolVersion ver, final int code) {
162        Args.notNegative(code, "Status code");
163        this.statusline = null;
164        this.ver = ver;
165        this.code = code;
166        this.reasonPhrase = null;
167    }
168
169    // non-javadoc, see interface HttpResponse
170    @Override
171    public void setStatusLine(
172            final ProtocolVersion ver, final int code, final String reason) {
173        Args.notNegative(code, "Status code");
174        this.statusline = null;
175        this.ver = ver;
176        this.code = code;
177        this.reasonPhrase = reason;
178    }
179
180    // non-javadoc, see interface HttpResponse
181    @Override
182    public void setStatusCode(final int code) {
183        Args.notNegative(code, "Status code");
184        this.statusline = null;
185        this.code = code;
186        this.reasonPhrase = null;
187    }
188
189    // non-javadoc, see interface HttpResponse
190    @Override
191    public void setReasonPhrase(final String reason) {
192        this.statusline = null;
193        this.reasonPhrase = reason;
194    }
195
196    // non-javadoc, see interface HttpResponse
197    @Override
198    public void setEntity(final HttpEntity entity) {
199        this.entity = entity;
200    }
201
202    @Override
203    public void setLocale(final Locale locale) {
204        this.locale = Args.notNull(locale, "Locale");
205        this.statusline = null;
206    }
207
208    /**
209     * Looks up a reason phrase.
210     * This method evaluates the currently set catalog and locale.
211     * It also handles a missing catalog.
212     *
213     * @param code      the status code for which to look up the reason
214     *
215     * @return  the reason phrase, or {@code null} if there is none
216     */
217    protected String getReason(final int code) {
218        return this.reasonCatalog != null ? this.reasonCatalog.getReason(code,
219                this.locale != null ? this.locale : Locale.getDefault()) : null;
220    }
221
222    @Override
223    public String toString() {
224        final StringBuilder sb = new StringBuilder();
225        sb.append(getStatusLine());
226        sb.append(' ');
227        sb.append(this.headergroup);
228        if (this.entity != null) {
229            sb.append(' ');
230            sb.append(this.entity);
231        }
232        return sb.toString();
233    }
234
235}