001/*
002 * Copyright 2008-2011 Thomas Nichols.  http://blog.thomnichols.org
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * You are receiving this code free of charge, which represents many hours of
017 * effort from other individuals and corporations.  As a responsible member
018 * of the community, you are encouraged (but not required) to donate any
019 * enhancements or improvements back to the community under a similar open
020 * source license.  Thank you. -TMN
021 */
022package groovyx.net.http;
023
024import java.util.Iterator;
025import java.util.Locale;
026
027import org.apache.http.Header;
028import org.apache.http.HeaderIterator;
029import org.apache.http.HttpEntity;
030import org.apache.http.HttpResponse;
031import org.apache.http.ProtocolVersion;
032import org.apache.http.StatusLine;
033import org.apache.http.params.HttpParams;
034import org.apache.http.protocol.ExecutionContext;
035import org.apache.http.protocol.HttpContext;
036
037/**
038 * This class is a wrapper for {@link HttpResponse}, which allows for
039 * simplified header access, as well as carrying the auto-parsed response data.
040 * (see {@link HTTPBuilder#parseResponse(HttpResponse, Object)}).
041 *
042 * @see HeadersDecorator
043 * @author <a href='mailto:[email protected]'>Tom Nichols</a>
044 * @since 0.5.0
045 */
046public class HttpResponseDecorator implements HttpResponse {
047
048    HeadersDecorator headers = null;
049    HttpResponse responseBase;
050    HttpContextDecorator context;
051    Object responseData;
052
053    public HttpResponseDecorator( HttpResponse base, Object parsedResponse ) {
054        this( base, null, parsedResponse );
055    }
056
057    public HttpResponseDecorator( HttpResponse base, HttpContextDecorator context, Object parsedResponse ) {
058        this.responseBase = base;
059        this.context = context;
060        this.responseData = parsedResponse;
061    }
062
063    /**
064     * Return a {@link HeadersDecorator}, which provides a more Groovy API for
065     * accessing response headers.
066     * @return the headers for this response
067     */
068    public HeadersDecorator getHeaders() {
069        if ( headers == null ) headers = new HeadersDecorator();
070        return headers;
071    }
072
073    /**
074     * Quickly determine if the request resulted in an error code.
075     * @return true if the response code is within the range of
076     *   {@link Status#SUCCESS}
077     */
078    public boolean isSuccess() {
079        return Status.find( getStatus() ) == Status.SUCCESS;
080    }
081
082    /**
083     * Get the response status code.
084     * @see StatusLine#getStatusCode()
085     * @return the HTTP response code.
086     */
087    public int getStatus() {
088        return responseBase.getStatusLine().getStatusCode();
089    }
090
091    /**
092     * Get the content-type for this response.
093     * @see ParserRegistry#getContentType(HttpResponse)
094     * @return the content-type string, without any charset information.
095     */
096    public String getContentType() {
097        return ParserRegistry.getContentType( responseBase );
098    }
099
100    /**
101     * Return the parsed data from this response body.
102     * @return the parsed response object, or <code>null</code> if the response
103     * does not contain any data.
104     */
105    public Object getData() { return this.responseData; }
106
107    void setData( Object responseData ) { this.responseData = responseData; }
108
109    /**
110     * Get the execution context used during this request
111     * @see ExecutionContext
112     * @return the {@link HttpContext}
113     */
114    public HttpContextDecorator getContext() { return this.context; }
115
116    /**
117     * This class is returned by {@link HttpResponseDecorator#getHeaders()}.
118     * It provides three "Groovy" ways to access headers:
119     * <dl>
120     *   <dt>Bracket notation</dt><dd><code>resp.headers['Content-Type']</code>
121     *      returns the {@link Header} instance</dd>
122     *   <dt>Property notation</dt><dd><code>resp.headers.'Content-Type'</code>
123     *      returns the {@link Header#getValue() header value}</dd>
124     *   <dt>Iterator methods</dt><dd>Iterates over each Header:
125     * <pre>resp.headers.each {
126     *   println "${it.name} : ${it.value}"
127     * }</pre></dd>
128     * </dl>
129     * @author <a href='mailto:[email protected]'>Tom Nichols</a>
130     * @since 0.5.0
131     */
132    public final class HeadersDecorator implements Iterable<Header> {
133
134        /**
135         * Access the named header value, using bracket form.  For example,
136         * <code>response.headers['Content-Encoding']</code>
137         * @see HttpResponse#getFirstHeader(String)
138         * @param name header name, e.g. <code>Content-Type<code>
139         * @return the {@link Header}, or <code>null</code> if it does not exist
140         *  in this response
141         */
142        public Header getAt( String name ) {
143            return responseBase.getFirstHeader( name );
144        }
145
146        /**
147         * Allow property-style access to header values.  This is the same as
148         * {@link #getAt(String)}, except it simply returns the header's String
149         * value, instead of the Header object.
150         *
151         * @param name header name, e.g. <code>Content-Type<code>
152         * @return the {@link Header}, or <code>null</code> if it does not exist
153         *  in this response
154         */
155        protected String propertyMissing( String name ) {
156            Header h = this.getAt( name );
157            return h != null ? h.getValue() : null;
158        }
159
160        /**
161         * Used to allow Groovy iteration methods over the response headers.
162         * For example:
163         * <pre>response.headers.each {
164         *   println "${it.name} : ${it.value}"
165         * }</pre>
166         */
167        @SuppressWarnings("unchecked")
168        public Iterator iterator() {
169            return responseBase.headerIterator();
170        }
171    }
172
173
174    public HttpEntity getEntity() {
175        return responseBase.getEntity();
176    }
177
178    public Locale getLocale() {
179        return responseBase.getLocale();
180    }
181
182    public StatusLine getStatusLine() {
183        return responseBase.getStatusLine();
184    }
185
186    public void setEntity( HttpEntity arg0 ) {
187        responseBase.setEntity( arg0 );
188    }
189
190    public void setLocale( Locale arg0 ) {
191        responseBase.setLocale( arg0 );
192    }
193
194    public void setReasonPhrase( String arg0 ) throws IllegalStateException {
195        responseBase.setReasonPhrase( arg0 );
196    }
197
198    public void setStatusCode( int arg0 ) throws IllegalStateException {
199        responseBase.setStatusCode( arg0 );
200    }
201
202    public void setStatusLine( StatusLine arg0 ) {
203        responseBase.setStatusLine( arg0 );
204    }
205
206    public void setStatusLine( ProtocolVersion arg0, int arg1 ) {
207        responseBase.setStatusLine( arg0, arg1 );
208    }
209
210    public void setStatusLine( ProtocolVersion arg0, int arg1, String arg2 ) {
211        responseBase.setStatusLine( arg0, arg1, arg2 );
212    }
213
214    public void addHeader( Header arg0 ) {
215        responseBase.addHeader( arg0 );
216    }
217
218    public void addHeader( String arg0, String arg1 ) {
219        responseBase.addHeader( arg0, arg1 );
220    }
221
222    public boolean containsHeader( String arg0 ) {
223        return responseBase.containsHeader( arg0 );
224    }
225
226    public Header[] getAllHeaders() {
227        return responseBase.getAllHeaders();
228    }
229
230    public Header getFirstHeader( String arg0 ) {
231        return responseBase.getFirstHeader( arg0 );
232    }
233
234    public Header[] getHeaders( String arg0 ) {
235        return responseBase.getHeaders( arg0 );
236    }
237
238    public Header getLastHeader( String arg0 ) {
239        return responseBase.getLastHeader( arg0 );
240    }
241
242    public HttpParams getParams() {
243        return responseBase.getParams();
244    }
245
246    public ProtocolVersion getProtocolVersion() {
247        return responseBase.getProtocolVersion();
248    }
249
250    public HeaderIterator headerIterator() {
251        return responseBase.headerIterator();
252    }
253
254    public HeaderIterator headerIterator( String arg0 ) {
255        return responseBase.headerIterator( arg0 );
256    }
257
258    public void removeHeader( Header arg0 ) {
259        responseBase.removeHeader( arg0 );
260    }
261
262    public void removeHeaders( String arg0 ) {
263        responseBase.removeHeaders( arg0 );
264    }
265
266    public void setHeader( Header arg0 ) {
267        responseBase.setHeader( arg0 );
268    }
269
270    public void setHeader( String arg0, String arg1 ) {
271        responseBase.setHeader( arg0, arg1 );
272    }
273
274    public void setHeaders( Header[] arg0 ) {
275        responseBase.setHeaders( arg0 );
276    }
277
278    public void setParams( HttpParams arg0 ) {
279        responseBase.setParams( arg0 );
280    }
281}