View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.http.client.cache;
28  
29  import java.io.Serializable;
30  import java.util.Collections;
31  import java.util.Date;
32  import java.util.HashMap;
33  import java.util.Map;
34  
35  import org.apache.http.Header;
36  import org.apache.http.HeaderIterator;
37  import org.apache.http.ProtocolVersion;
38  import org.apache.http.StatusLine;
39  import org.apache.http.annotation.Immutable;
40  import org.apache.http.client.utils.DateUtils;
41  import org.apache.http.message.HeaderGroup;
42  import org.apache.http.protocol.HTTP;
43  import org.apache.http.util.Args;
44  
45  /**
46   * Structure used to store an {@link org.apache.http.HttpResponse} in a cache.
47   * Some entries can optionally depend on system resources that may require
48   * explicit deallocation. In such a case {@link #getResource()} should return
49   * a non null instance of {@link Resource} that must be deallocated by calling
50   * {@link Resource#dispose()} method when no longer used.
51   *
52   * @since 4.1
53   */
54  @Immutable
55  public class HttpCacheEntry implements Serializable {
56  
57      private static final long serialVersionUID = -6300496422359477413L;
58      private static final String REQUEST_METHOD_HEADER_NAME = "Hc-Request-Method";
59  
60      private final Date requestDate;
61      private final Date responseDate;
62      private final StatusLine statusLine;
63      private final HeaderGroup responseHeaders;
64      private final Resource resource;
65      private final Map<String,String> variantMap;
66      private final Date date;
67  
68      /**
69       * Create a new {@link HttpCacheEntry} with variants.
70       * @param requestDate
71       *          Date/time when the request was made (Used for age
72       *            calculations)
73       * @param responseDate
74       *          Date/time that the response came back (Used for age
75       *            calculations)
76       * @param statusLine
77       *          HTTP status line from origin response
78       * @param responseHeaders
79       *          Header[] from original HTTP Response
80       * @param resource representing origin response body
81       * @param variantMap describing cache entries that are variants
82       *   of this parent entry; this maps a "variant key" (derived
83       *   from the varying request headers) to a "cache key" (where
84       *   in the cache storage the particular variant is located)
85       * @param requestMethod HTTP method used when the request was made
86       */
87      public HttpCacheEntry(
88              final Date requestDate,
89              final Date responseDate,
90              final StatusLine statusLine,
91              final Header[] responseHeaders,
92              final Resource resource,
93              final Map<String,String> variantMap,
94              final String requestMethod) {
95          super();
96          Args.notNull(requestDate, "Request date");
97          Args.notNull(responseDate, "Response date");
98          Args.notNull(statusLine, "Status line");
99          Args.notNull(responseHeaders, "Response headers");
100         this.requestDate = requestDate;
101         this.responseDate = responseDate;
102         this.statusLine = statusLine;
103         this.responseHeaders = new HeaderGroup();
104         this.responseHeaders.setHeaders(responseHeaders);
105         this.resource = resource;
106         this.variantMap = variantMap != null
107             ? new HashMap<String,String>(variantMap)
108             : null;
109         this.date = parseDate();
110     }
111 
112     /**
113      * Create a new {@link HttpCacheEntry} with variants.
114      * @param requestDate
115      *          Date/time when the request was made (Used for age
116      *            calculations)
117      * @param responseDate
118      *          Date/time that the response came back (Used for age
119      *            calculations)
120      * @param statusLine
121      *          HTTP status line from origin response
122      * @param responseHeaders
123      *          Header[] from original HTTP Response
124      * @param resource representing origin response body
125      * @param variantMap describing cache entries that are variants
126      *   of this parent entry; this maps a "variant key" (derived
127      *   from the varying request headers) to a "cache key" (where
128      *   in the cache storage the particular variant is located)
129      */
130     public HttpCacheEntry(
131             final Date requestDate,
132             final Date responseDate,
133             final StatusLine statusLine,
134             final Header[] responseHeaders,
135             final Resource resource,
136             final Map<String,String> variantMap) {
137         this(requestDate, responseDate, statusLine, responseHeaders, resource,
138                 variantMap, null);
139     }
140 
141     /**
142      * Create a new {@link HttpCacheEntry}.
143      *
144      * @param requestDate
145      *          Date/time when the request was made (Used for age
146      *            calculations)
147      * @param responseDate
148      *          Date/time that the response came back (Used for age
149      *            calculations)
150      * @param statusLine
151      *          HTTP status line from origin response
152      * @param responseHeaders
153      *          Header[] from original HTTP Response
154      * @param resource representing origin response body
155      */
156     public HttpCacheEntry(final Date requestDate, final Date responseDate, final StatusLine statusLine,
157             final Header[] responseHeaders, final Resource resource) {
158         this(requestDate, responseDate, statusLine, responseHeaders, resource,
159                 new HashMap<String,String>());
160     }
161 
162     /**
163      * Create a new {@link HttpCacheEntry}.
164      *
165      * @param requestDate
166      *          Date/time when the request was made (Used for age
167      *            calculations)
168      * @param responseDate
169      *          Date/time that the response came back (Used for age
170      *            calculations)
171      * @param statusLine
172      *          HTTP status line from origin response
173      * @param responseHeaders
174      *          Header[] from original HTTP Response
175      * @param resource representing origin response body
176      * @param requestMethod HTTP method used when the request was made
177      */
178     public HttpCacheEntry(final Date requestDate, final Date responseDate, final StatusLine statusLine,
179             final Header[] responseHeaders, final Resource resource, final String requestMethod) {
180         this(requestDate, responseDate, statusLine, responseHeaders, resource,
181                 new HashMap<String,String>(),requestMethod);
182     }
183 
184     /**
185      * Find the "Date" response header and parse it into a java.util.Date
186      * @return the Date value of the header or null if the header is not present
187      */
188     private Date parseDate() {
189         final Header dateHdr = getFirstHeader(HTTP.DATE_HEADER);
190         if (dateHdr == null) {
191             return null;
192         }
193         return DateUtils.parseDate(dateHdr.getValue());
194     }
195 
196     /**
197      * Returns the {@link StatusLine} from the origin
198      * {@link org.apache.http.HttpResponse}.
199      */
200     public StatusLine getStatusLine() {
201         return this.statusLine;
202     }
203 
204     /**
205      * Returns the {@link ProtocolVersion} from the origin
206      * {@link org.apache.http.HttpResponse}.
207      */
208     public ProtocolVersion getProtocolVersion() {
209         return this.statusLine.getProtocolVersion();
210     }
211 
212     /**
213      * Gets the reason phrase from the origin
214      * {@link org.apache.http.HttpResponse}, for example, "Not Modified".
215      */
216     public String getReasonPhrase() {
217         return this.statusLine.getReasonPhrase();
218     }
219 
220     /**
221      * Returns the HTTP response code from the origin
222      * {@link org.apache.http.HttpResponse}.
223      */
224     public int getStatusCode() {
225         return this.statusLine.getStatusCode();
226     }
227 
228     /**
229      * Returns the time the associated origin request was initiated by the
230      * caching module.
231      * @return {@link Date}
232      */
233     public Date getRequestDate() {
234         return requestDate;
235     }
236 
237     /**
238      * Returns the time the origin response was received by the caching module.
239      * @return {@link Date}
240      */
241     public Date getResponseDate() {
242         return responseDate;
243     }
244 
245     /**
246      * Returns all the headers that were on the origin response.
247      */
248     public Header[] getAllHeaders() {
249         final HeaderGroup filteredHeaders = new HeaderGroup();
250         for (final HeaderIterator iterator = responseHeaders.iterator(); iterator
251                 .hasNext();) {
252             final Header header = (Header) iterator.next();
253             if (!REQUEST_METHOD_HEADER_NAME.equals(header.getName())) {
254                 filteredHeaders.addHeader(header);
255             }
256         }
257         return filteredHeaders.getAllHeaders();
258     }
259 
260     /**
261      * Returns the first header from the origin response with the given
262      * name.
263      */
264     public Header getFirstHeader(final String name) {
265         if (REQUEST_METHOD_HEADER_NAME.equalsIgnoreCase(name)) {
266             return null;
267         }
268         return responseHeaders.getFirstHeader(name);
269     }
270 
271     /**
272      * Gets all the headers with the given name that were on the origin
273      * response.
274      */
275     public Header[] getHeaders(final String name) {
276         if (REQUEST_METHOD_HEADER_NAME.equalsIgnoreCase(name)) {
277             return new Header[0];
278         }
279         return responseHeaders.getHeaders(name);
280     }
281 
282     /**
283      * Gets the Date value of the "Date" header or null if the header is missing or cannot be
284      * parsed.
285      *
286      * @since 4.3
287      */
288     public Date getDate() {
289         return date;
290     }
291 
292     /**
293      * Returns the {@link Resource} containing the origin response body.
294      */
295     public Resource getResource() {
296         return this.resource;
297     }
298 
299     /**
300      * Indicates whether the origin response indicated the associated
301      * resource had variants (i.e. that the Vary header was set on the
302      * origin response).
303      * @return {@code true} if this cached response was a variant
304      */
305     public boolean hasVariants() {
306         return getFirstHeader(HeaderConstants.VARY) != null;
307     }
308 
309     /**
310      * Returns an index about where in the cache different variants for
311      * a given resource are stored. This maps "variant keys" to "cache keys",
312      * where the variant key is derived from the varying request headers,
313      * and the cache key is the location in the
314      * {@link org.apache.http.client.cache.HttpCacheStorage} where that
315      * particular variant is stored. The first variant returned is used as
316      * the "parent" entry to hold this index of the other variants.
317      */
318     public Map<String, String> getVariantMap() {
319         return Collections.unmodifiableMap(variantMap);
320     }
321 
322     /**
323      * Returns the HTTP request method that was used to create the cached
324      * response entry.
325      *
326      * @since 4.4
327      */
328     public String getRequestMethod() {
329         final Header requestMethodHeader = responseHeaders
330                 .getFirstHeader(REQUEST_METHOD_HEADER_NAME);
331         if (requestMethodHeader != null) {
332             return requestMethodHeader.getValue();
333         }
334         return HeaderConstants.GET_METHOD;
335     }
336 
337     /**
338      * Provides a string representation of this instance suitable for
339      * human consumption.
340      */
341     @Override
342     public String toString() {
343         return "[request date=" + this.requestDate + "; response date=" + this.responseDate
344                 + "; statusLine=" + this.statusLine + "]";
345     }
346 
347 }