Refactored HttpCacheEntry / Resource API: HttpCacheEntry is no longer abstract; the same class can be used with any Resource implementations
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@984197 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1b58a2360d
commit
cb4f012fa7
|
@ -27,7 +27,6 @@
|
|||
package org.apache.http.client.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
@ -52,7 +51,7 @@ import org.apache.http.message.BasicHeader;
|
|||
* @since 4.1
|
||||
*/
|
||||
@Immutable
|
||||
public abstract class HttpCacheEntry implements Serializable {
|
||||
public class HttpCacheEntry implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6300496422359477413L;
|
||||
|
||||
|
@ -60,6 +59,7 @@ public abstract class HttpCacheEntry implements Serializable {
|
|||
private final Date responseDate;
|
||||
private final StatusLine statusLine;
|
||||
private final CachedHeaderGroup responseHeaders;
|
||||
private final Resource resource;
|
||||
private final Set<String> variantURIs;
|
||||
|
||||
/**
|
||||
|
@ -81,6 +81,7 @@ public abstract class HttpCacheEntry implements Serializable {
|
|||
final Date responseDate,
|
||||
final StatusLine statusLine,
|
||||
final Header[] responseHeaders,
|
||||
final Resource resource,
|
||||
final Set<String> variants) {
|
||||
super();
|
||||
if (requestDate == null) {
|
||||
|
@ -95,11 +96,15 @@ public abstract class HttpCacheEntry implements Serializable {
|
|||
if (responseHeaders == null) {
|
||||
throw new IllegalArgumentException("Response headers may not be null");
|
||||
}
|
||||
if (resource == null) {
|
||||
throw new IllegalArgumentException("Resource may not be null");
|
||||
}
|
||||
this.requestDate = requestDate;
|
||||
this.responseDate = responseDate;
|
||||
this.statusLine = statusLine;
|
||||
this.responseHeaders = new CachedHeaderGroup();
|
||||
this.responseHeaders.setHeaders(responseHeaders);
|
||||
this.resource = resource;
|
||||
this.variantURIs = variants != null ? new HashSet<String>(variants) : new HashSet<String>();
|
||||
}
|
||||
|
||||
|
@ -147,11 +152,9 @@ public abstract class HttpCacheEntry implements Serializable {
|
|||
return Collections.unmodifiableSet(this.variantURIs);
|
||||
}
|
||||
|
||||
public abstract Resource getResource();
|
||||
|
||||
public abstract InputStream getBody() throws IOException;
|
||||
|
||||
public abstract long getBodyLength();
|
||||
public Resource getResource() {
|
||||
return this.resource;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
|
||||
|
|
|
@ -26,12 +26,20 @@
|
|||
*/
|
||||
package org.apache.http.client.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represents a disposable system resource.
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
public interface Resource {
|
||||
public interface Resource extends Serializable {
|
||||
|
||||
InputStream getInputStream() throws IOException;
|
||||
|
||||
long length();
|
||||
|
||||
void dispose();
|
||||
|
||||
|
|
|
@ -66,18 +66,18 @@ class CacheEntity implements HttpEntity, Serializable {
|
|||
}
|
||||
|
||||
public long getContentLength() {
|
||||
return this.cacheEntry.getBodyLength();
|
||||
return this.cacheEntry.getResource().length();
|
||||
}
|
||||
|
||||
public InputStream getContent() throws IOException {
|
||||
return this.cacheEntry.getBody();
|
||||
return this.cacheEntry.getResource().getInputStream();
|
||||
}
|
||||
|
||||
public void writeTo(final OutputStream outstream) throws IOException {
|
||||
if (outstream == null) {
|
||||
throw new IllegalArgumentException("Output stream may not be null");
|
||||
}
|
||||
InputStream instream = this.cacheEntry.getBody();
|
||||
InputStream instream = this.cacheEntry.getResource().getInputStream();
|
||||
try {
|
||||
IOUtils.copy(instream, outstream);
|
||||
} finally {
|
||||
|
|
|
@ -86,7 +86,7 @@ class CacheEntryUpdater {
|
|||
|
||||
Header[] mergedHeaders = mergeHeaders(entry, response);
|
||||
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
|
||||
InputStream instream = entry.getBody();
|
||||
InputStream instream = entry.getResource().getInputStream();
|
||||
byte[] buf = new byte[2048];
|
||||
int len;
|
||||
while ((len = instream.read(buf)) != -1) {
|
||||
|
|
|
@ -140,7 +140,7 @@ class CacheValidityPolicy {
|
|||
* @return boolean indicating whether actual length matches Content-Length
|
||||
*/
|
||||
protected boolean contentLengthHeaderMatchesActualLength(final HttpCacheEntry entry) {
|
||||
return getContentLengthValue(entry) == entry.getBodyLength();
|
||||
return getContentLengthValue(entry) == entry.getResource().length();
|
||||
}
|
||||
|
||||
protected long getApparentAgeSecs(final HttpCacheEntry entry) {
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.apache.http.StatusLine;
|
|||
import org.apache.http.annotation.Immutable;
|
||||
import org.apache.http.client.cache.HttpCacheEntry;
|
||||
import org.apache.http.client.cache.HttpCacheEntryFactory;
|
||||
import org.apache.http.client.cache.Resource;
|
||||
|
||||
/**
|
||||
* Generates {@link HttpCacheEntry} instances whose body is stored in a temporary file.
|
||||
|
@ -56,14 +57,7 @@ public class FileCacheEntryFactory implements HttpCacheEntryFactory {
|
|||
this.idgen = new BasicIdGenerator();
|
||||
}
|
||||
|
||||
public HttpCacheEntry generate(
|
||||
final String requestId,
|
||||
final Date requestDate,
|
||||
final Date responseDate,
|
||||
final StatusLine statusLine,
|
||||
final Header[] headers,
|
||||
byte[] body) throws IOException {
|
||||
|
||||
private File generateUniqueCacheFile(final String requestId) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
this.idgen.generate(buffer);
|
||||
buffer.append('.');
|
||||
|
@ -76,19 +70,29 @@ public class FileCacheEntryFactory implements HttpCacheEntryFactory {
|
|||
buffer.append('-');
|
||||
}
|
||||
}
|
||||
File file = new File(this.cacheDir, buffer.toString());
|
||||
return new File(this.cacheDir, buffer.toString());
|
||||
}
|
||||
|
||||
public HttpCacheEntry generate(
|
||||
final String requestId,
|
||||
final Date requestDate,
|
||||
final Date responseDate,
|
||||
final StatusLine statusLine,
|
||||
final Header[] headers,
|
||||
byte[] body) throws IOException {
|
||||
File file = generateUniqueCacheFile(requestId);
|
||||
FileOutputStream outstream = new FileOutputStream(file);
|
||||
try {
|
||||
outstream.write(body);
|
||||
} finally {
|
||||
outstream.close();
|
||||
}
|
||||
return new FileCacheEntry(
|
||||
return new HttpCacheEntry(
|
||||
requestDate,
|
||||
responseDate,
|
||||
statusLine,
|
||||
headers,
|
||||
file,
|
||||
new FileResource(file),
|
||||
null);
|
||||
}
|
||||
|
||||
|
@ -97,25 +101,25 @@ public class FileCacheEntryFactory implements HttpCacheEntryFactory {
|
|||
final HttpCacheEntry entry,
|
||||
final String variantURI) throws IOException {
|
||||
|
||||
String uid = this.idgen.generate();
|
||||
File file = new File(this.cacheDir, uid + "-" + requestId);
|
||||
File file = generateUniqueCacheFile(requestId);
|
||||
|
||||
Set<String> variants = new HashSet<String>(entry.getVariantURIs());
|
||||
variants.add(variantURI);
|
||||
|
||||
if (entry instanceof FileCacheEntry) {
|
||||
File src = ((FileCacheEntry) entry).getRawBody();
|
||||
Resource orig = entry.getResource();
|
||||
if (orig instanceof FileResource) {
|
||||
File src = ((FileResource) orig).getFile();
|
||||
IOUtils.copyFile(src, file);
|
||||
} else {
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
IOUtils.copyAndClose(entry.getBody(), out);
|
||||
IOUtils.copyAndClose(orig.getInputStream(), out);
|
||||
}
|
||||
return new FileCacheEntry(
|
||||
return new HttpCacheEntry(
|
||||
entry.getRequestDate(),
|
||||
entry.getResponseDate(),
|
||||
entry.getStatusLine(),
|
||||
entry.getAllHeaders(),
|
||||
file,
|
||||
new FileResource(file),
|
||||
variants);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,73 +30,57 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.annotation.Immutable;
|
||||
import org.apache.http.client.cache.HttpCacheEntry;
|
||||
import org.apache.http.annotation.ThreadSafe;
|
||||
import org.apache.http.client.cache.Resource;
|
||||
|
||||
/**
|
||||
* {@link File} backed {@link HttpCacheEntry} that requires explicit deallocation.
|
||||
* Cache resource backed by a file.
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
@Immutable
|
||||
class FileCacheEntry extends HttpCacheEntry {
|
||||
@ThreadSafe
|
||||
class FileResource implements Resource {
|
||||
|
||||
private static final long serialVersionUID = -8396589100351931966L;
|
||||
private static final long serialVersionUID = 4132244415919043397L;
|
||||
|
||||
private final File file;
|
||||
private final FileResource resource;
|
||||
|
||||
public FileCacheEntry(
|
||||
final Date requestDate,
|
||||
final Date responseDate,
|
||||
final StatusLine statusLine,
|
||||
final Header[] responseHeaders,
|
||||
final File file,
|
||||
final Set<String> variants) {
|
||||
super(requestDate, responseDate, statusLine, responseHeaders, variants);
|
||||
private volatile boolean disposed;
|
||||
|
||||
public FileResource(final File file) {
|
||||
super();
|
||||
this.file = file;
|
||||
this.resource = new FileResource(file);
|
||||
this.disposed = false;
|
||||
}
|
||||
|
||||
File getRawBody() {
|
||||
private void ensureValid() {
|
||||
if (this.disposed) {
|
||||
throw new IllegalStateException("Resource has been deallocated");
|
||||
}
|
||||
}
|
||||
|
||||
synchronized File getFile() {
|
||||
ensureValid();
|
||||
return this.file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBodyLength() {
|
||||
return this.file.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
public synchronized InputStream getInputStream() throws IOException {
|
||||
ensureValid();
|
||||
return new FileInputStream(this.file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource() {
|
||||
return this.resource;
|
||||
public synchronized long length() {
|
||||
ensureValid();
|
||||
return this.file.length();
|
||||
}
|
||||
|
||||
class FileResource implements Resource {
|
||||
|
||||
private File file;
|
||||
|
||||
FileResource(final File file) {
|
||||
super();
|
||||
this.file = file;
|
||||
public synchronized void dispose() {
|
||||
if (this.disposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
public synchronized void dispose() {
|
||||
if (this.file != null) {
|
||||
this.file.delete();
|
||||
this.file = null;
|
||||
}
|
||||
}
|
||||
|
||||
this.disposed = true;
|
||||
this.file.delete();
|
||||
}
|
||||
|
||||
}
|
|
@ -28,54 +28,40 @@ package org.apache.http.impl.client.cache;
|
|||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.annotation.Immutable;
|
||||
import org.apache.http.client.cache.HttpCacheEntry;
|
||||
import org.apache.http.client.cache.Resource;
|
||||
|
||||
/**
|
||||
* Basic {@link HttpCacheEntry} that does not depend on any system resources that may require
|
||||
* explicit deallocation.
|
||||
* Cache resource backed by a byte array on the heap.
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
@Immutable
|
||||
class MemCacheEntry extends HttpCacheEntry {
|
||||
class HeapResource implements Resource {
|
||||
|
||||
private static final long serialVersionUID = -8464486112875881235L;
|
||||
private static final long serialVersionUID = -2078599905620463394L;
|
||||
|
||||
private final byte[] body;
|
||||
private final byte[] b;
|
||||
|
||||
public MemCacheEntry(
|
||||
final Date requestDate,
|
||||
final Date responseDate,
|
||||
final StatusLine statusLine,
|
||||
final Header[] responseHeaders,
|
||||
final byte[] body,
|
||||
final Set<String> variants) {
|
||||
super(requestDate, responseDate, statusLine, responseHeaders, variants);
|
||||
this.body = body;
|
||||
public HeapResource(final byte[] b) {
|
||||
super();
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
byte[] getRawBody() {
|
||||
return this.body;
|
||||
byte[] getByteArray() {
|
||||
return this.b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBodyLength() {
|
||||
return this.body.length;
|
||||
public InputStream getInputStream() {
|
||||
return new ByteArrayInputStream(this.b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() {
|
||||
return new ByteArrayInputStream(this.body);
|
||||
public long length() {
|
||||
return this.b.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource() {
|
||||
return null;
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
}
|
|
@ -38,6 +38,7 @@ import org.apache.http.StatusLine;
|
|||
import org.apache.http.annotation.Immutable;
|
||||
import org.apache.http.client.cache.HttpCacheEntry;
|
||||
import org.apache.http.client.cache.HttpCacheEntryFactory;
|
||||
import org.apache.http.client.cache.Resource;
|
||||
|
||||
/**
|
||||
* Generates {@link HttpCacheEntry} instances stored entirely in memory.
|
||||
|
@ -52,11 +53,11 @@ public class MemCacheEntryFactory implements HttpCacheEntryFactory {
|
|||
final Date responseDate,
|
||||
final HttpResponse response,
|
||||
final byte[] body) {
|
||||
return new MemCacheEntry(requestDate,
|
||||
return new HttpCacheEntry(requestDate,
|
||||
responseDate,
|
||||
response.getStatusLine(),
|
||||
response.getAllHeaders(),
|
||||
body,
|
||||
new HeapResource(body),
|
||||
null);
|
||||
}
|
||||
|
||||
|
@ -67,11 +68,11 @@ public class MemCacheEntryFactory implements HttpCacheEntryFactory {
|
|||
final StatusLine statusLine,
|
||||
final Header[] headers,
|
||||
byte[] body) throws IOException {
|
||||
return new MemCacheEntry(requestDate,
|
||||
return new HttpCacheEntry(requestDate,
|
||||
responseDate,
|
||||
statusLine,
|
||||
headers,
|
||||
body,
|
||||
new HeapResource(body),
|
||||
null);
|
||||
}
|
||||
|
||||
|
@ -80,23 +81,25 @@ public class MemCacheEntryFactory implements HttpCacheEntryFactory {
|
|||
final HttpCacheEntry entry,
|
||||
final String variantURI) throws IOException {
|
||||
byte[] body;
|
||||
if (entry instanceof MemCacheEntry) {
|
||||
body = ((MemCacheEntry) entry).getRawBody();
|
||||
|
||||
Resource orig = entry.getResource();
|
||||
if (orig instanceof HeapResource) {
|
||||
body = ((HeapResource) orig).getByteArray();
|
||||
} else {
|
||||
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
|
||||
IOUtils.copyAndClose(entry.getBody(), outstream);
|
||||
IOUtils.copyAndClose(orig.getInputStream(), outstream);
|
||||
body = outstream.toByteArray();
|
||||
}
|
||||
|
||||
Set<String> variants = new HashSet<String>(entry.getVariantURIs());
|
||||
variants.add(variantURI);
|
||||
|
||||
return new MemCacheEntry(
|
||||
return new HttpCacheEntry(
|
||||
entry.getRequestDate(),
|
||||
entry.getResponseDate(),
|
||||
entry.getStatusLine(),
|
||||
entry.getAllHeaders(),
|
||||
body,
|
||||
new HeapResource(body),
|
||||
variants);
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ class SizeLimitedResponseReader {
|
|||
return isTooLarge;
|
||||
}
|
||||
|
||||
private synchronized boolean consumeResponse() throws IOException {
|
||||
private boolean consumeResponse() throws IOException {
|
||||
|
||||
if (responseIsConsumed)
|
||||
throw new IllegalStateException(
|
||||
|
@ -106,7 +106,7 @@ class SizeLimitedResponseReader {
|
|||
return false;
|
||||
}
|
||||
|
||||
private synchronized void consumeOutputStream() {
|
||||
private void consumeOutputStream() {
|
||||
if (outputStreamConsumed)
|
||||
throw new IllegalStateException(
|
||||
"underlying output stream has already been written to byte[]");
|
||||
|
|
|
@ -29,24 +29,27 @@ package org.apache.http.impl.client.cache;
|
|||
import java.util.Date;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.client.cache.HttpCacheEntry;
|
||||
import org.apache.http.client.cache.Resource;
|
||||
|
||||
public class CacheEntry extends MemCacheEntry {
|
||||
public class CacheEntry extends HttpCacheEntry {
|
||||
|
||||
private static final long serialVersionUID = 7964121802841871079L;
|
||||
|
||||
private static Resource BODY = new HeapResource(new byte[] {});
|
||||
public static final long MAX_AGE = CacheValidityPolicy.MAX_AGE;
|
||||
|
||||
public CacheEntry(
|
||||
Date requestDate,
|
||||
Date responseDate) {
|
||||
super(requestDate, responseDate, new OKStatus(), new Header[] {}, new byte[] {}, null);
|
||||
super(requestDate, responseDate, new OKStatus(), new Header[] {}, BODY, null);
|
||||
}
|
||||
|
||||
public CacheEntry(
|
||||
Date requestDate,
|
||||
Date responseDate,
|
||||
Header[] headers) {
|
||||
super(requestDate, responseDate, new OKStatus(), headers, new byte[] {}, null);
|
||||
super(requestDate, responseDate, new OKStatus(), headers, BODY, null);
|
||||
}
|
||||
|
||||
public CacheEntry(
|
||||
|
@ -54,17 +57,17 @@ public class CacheEntry extends MemCacheEntry {
|
|||
Date responseDate,
|
||||
Header[] headers,
|
||||
byte[] content) {
|
||||
super(requestDate, responseDate, new OKStatus(), headers, content, null);
|
||||
super(requestDate, responseDate, new OKStatus(), headers, new HeapResource(content), null);
|
||||
}
|
||||
|
||||
public CacheEntry(
|
||||
Header[] headers,
|
||||
byte[] content) {
|
||||
super(new Date(), new Date(), new OKStatus(), headers, content, null);
|
||||
super(new Date(), new Date(), new OKStatus(), headers, new HeapResource(content), null);
|
||||
}
|
||||
|
||||
public CacheEntry(Header[] headers) {
|
||||
super(new Date(), new Date(), new OKStatus(), headers, new byte[] {}, null);
|
||||
super(new Date(), new Date(), new OKStatus(), headers, BODY, null);
|
||||
}
|
||||
|
||||
public CacheEntry() {
|
||||
|
@ -72,7 +75,7 @@ public class CacheEntry extends MemCacheEntry {
|
|||
}
|
||||
|
||||
public CacheEntry(byte[] content) {
|
||||
super(new Date(), new Date(), new OKStatus(), new Header[] {}, content, null);
|
||||
super(new Date(), new Date(), new OKStatus(), new Header[] {}, new HeapResource(content), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -144,12 +144,12 @@ public class TestResponseCache {
|
|||
cache.updateEntry("foo", new HttpCacheUpdateCallback() {
|
||||
|
||||
public HttpCacheEntry update(HttpCacheEntry existing) {
|
||||
HttpCacheEntry updated = new MemCacheEntry(
|
||||
HttpCacheEntry updated = new HttpCacheEntry(
|
||||
existing.getRequestDate(),
|
||||
existing.getRequestDate(),
|
||||
existing.getStatusLine(),
|
||||
existing.getAllHeaders(),
|
||||
expectedArray,
|
||||
new HeapResource(expectedArray),
|
||||
null);
|
||||
return updated;
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ public class TestResponseCache {
|
|||
HttpCacheEntry afterUpdate = cache.getEntry("foo");
|
||||
|
||||
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
|
||||
InputStream instream = afterUpdate.getBody();
|
||||
InputStream instream = afterUpdate.getResource().getInputStream();
|
||||
byte[] buf = new byte[2048];
|
||||
int len;
|
||||
while ((len = instream.read(buf)) != -1) {
|
||||
|
|
Loading…
Reference in New Issue