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 package org.apache.http.impl.client.cache;
28
29 import java.io.Closeable;
30 import java.io.IOException;
31 import java.lang.ref.PhantomReference;
32 import java.lang.ref.ReferenceQueue;
33 import java.util.HashSet;
34 import java.util.Set;
35
36 import org.apache.http.annotation.ThreadSafe;
37 import org.apache.http.client.cache.HttpCacheEntry;
38 import org.apache.http.client.cache.HttpCacheStorage;
39 import org.apache.http.client.cache.HttpCacheUpdateCallback;
40 import org.apache.http.client.cache.Resource;
41 import org.apache.http.util.Args;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 @ThreadSafe
58 public class ManagedHttpCacheStorage implements HttpCacheStorage, Closeable {
59
60 private final CacheMap entries;
61 private final ReferenceQueue<HttpCacheEntry> morque;
62 private final Set<ResourceReference> resources;
63
64 private volatile boolean shutdown;
65
66 public ManagedHttpCacheStorage(final CacheConfig config) {
67 super();
68 this.entries = new CacheMap(config.getMaxCacheEntries());
69 this.morque = new ReferenceQueue<HttpCacheEntry>();
70 this.resources = new HashSet<ResourceReference>();
71 }
72
73 private void ensureValidState() throws IllegalStateException {
74 if (this.shutdown) {
75 throw new IllegalStateException("Cache has been shut down");
76 }
77 }
78
79 private void keepResourceReference(final HttpCacheEntry entry) {
80 final Resource resource = entry.getResource();
81 if (resource != null) {
82
83 final ResourceReference ref = new ResourceReference(entry, this.morque);
84 this.resources.add(ref);
85 }
86 }
87
88 public void putEntry(final String url, final HttpCacheEntry entry) throws IOException {
89 Args.notNull(url, "URL");
90 Args.notNull(entry, "Cache entry");
91 ensureValidState();
92 synchronized (this) {
93 this.entries.put(url, entry);
94 keepResourceReference(entry);
95 }
96 }
97
98 public HttpCacheEntry getEntry(final String url) throws IOException {
99 Args.notNull(url, "URL");
100 ensureValidState();
101 synchronized (this) {
102 return this.entries.get(url);
103 }
104 }
105
106 public void removeEntry(final String url) throws IOException {
107 Args.notNull(url, "URL");
108 ensureValidState();
109 synchronized (this) {
110
111
112 this.entries.remove(url);
113 }
114 }
115
116 public void updateEntry(
117 final String url,
118 final HttpCacheUpdateCallback callback) throws IOException {
119 Args.notNull(url, "URL");
120 Args.notNull(callback, "Callback");
121 ensureValidState();
122 synchronized (this) {
123 final HttpCacheEntry existing = this.entries.get(url);
124 final HttpCacheEntry updated = callback.update(existing);
125 this.entries.put(url, updated);
126 if (existing != updated) {
127 keepResourceReference(updated);
128 }
129 }
130 }
131
132 public void cleanResources() {
133 if (this.shutdown) {
134 return;
135 }
136 ResourceReference ref;
137 while ((ref = (ResourceReference) this.morque.poll()) != null) {
138 synchronized (this) {
139 this.resources.remove(ref);
140 }
141 ref.getResource().dispose();
142 }
143 }
144
145 public void shutdown() {
146 if (this.shutdown) {
147 return;
148 }
149 this.shutdown = true;
150 synchronized (this) {
151 this.entries.clear();
152 for (final ResourceReference ref: this.resources) {
153 ref.getResource().dispose();
154 }
155 this.resources.clear();
156 while (this.morque.poll() != null) {
157 }
158 }
159 }
160
161 public void close() {
162 shutdown();
163 }
164
165 }