2 * Copyright (C) 2010 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.net.CacheRequest;
25 import java.net.CacheResponse;
26 import java.net.ResponseCache;
28 import java.net.URLConnection;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.LinkedHashMap;
32 import java.util.List;
36 * Cache all responses in memory by URI.
38 public final class DefaultResponseCache extends ResponseCache {
39 private final Map<URI, Entry> entries = new HashMap<URI, Entry>();
40 private int abortCount;
41 private int successCount;
43 private int missCount;
45 @Override public synchronized CacheResponse get(URI uri, String requestMethod,
46 Map<String, List<String>> requestHeaders) throws IOException {
47 // TODO: honor the request headers in the cache key
48 Entry entry = entries.get(uri);
51 return entry.asResponse();
58 @Override public CacheRequest put(URI uri, URLConnection urlConnection)
60 // TODO: honor the response headers for cache invalidation
61 return new Entry(uri, urlConnection).asRequest();
64 public synchronized Map<URI, Entry> getContents() {
65 return new HashMap<URI, Entry>(entries);
69 * Returns the number of requests that were aborted before they were closed.
71 public synchronized int getAbortCount() {
76 * Returns the number of requests that were closed successfully.
78 public synchronized int getSuccessCount() {
83 * Returns the number of responses served by the cache.
85 public synchronized int getHitCount() {
90 * Returns the number of responses that couldn't be served by the cache.
92 public synchronized int getMissCount() {
96 public final class Entry {
97 private final ByteArrayOutputStream bytesOut = new ByteArrayOutputStream() {
98 private boolean closed;
99 @Override public void close() throws IOException {
100 synchronized (DefaultResponseCache.this) {
106 entries.put(uri, Entry.this);
112 private final Map<String, List<String>> headers;
113 private final URI uri;
115 private Entry(URI uri, URLConnection conn) {
117 this.headers = deepCopy(conn.getHeaderFields());
120 public CacheRequest asRequest() {
121 return new CacheRequest() {
122 private boolean aborted;
123 @Override public void abort() {
124 synchronized (DefaultResponseCache.this) {
133 @Override public OutputStream getBody() throws IOException {
139 public CacheResponse asResponse() {
140 return new CacheResponse() {
141 @Override public InputStream getBody() throws IOException {
142 return new ByteArrayInputStream(getBytes());
144 @Override public Map<String, List<String>> getHeaders() throws IOException {
145 return deepCopy(headers);
150 public byte[] getBytes() {
151 return bytesOut.toByteArray();
155 private static Map<String, List<String>> deepCopy(Map<String, List<String>> input) {
156 Map<String, List<String>> result = new LinkedHashMap<String, List<String>>(input);
157 for (Map.Entry<String, List<String>> entry : result.entrySet()) {
158 entry.setValue(new ArrayList<String>(entry.getValue()));