Refactored HttpCacheEntry; new API should allow for cache entries backed by a temporary file

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@980937 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2010-07-30 20:15:39 +00:00
parent 4ae188acbb
commit e0d37d5502
14 changed files with 99 additions and 103 deletions

View File

@ -27,6 +27,7 @@
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;
@ -36,7 +37,6 @@ import java.util.HashSet;
import java.util.Set;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
@ -60,7 +60,6 @@ public abstract class HttpCacheEntry implements Serializable {
private final Date responseDate;
private final StatusLine statusLine;
private final CachedHeaderGroup responseHeaders;
private final HttpEntity body;
private final Set<String> variantURIs;
/**
@ -72,23 +71,16 @@ public abstract class HttpCacheEntry implements Serializable {
* @param responseDate
* Date/time that the response came back (Used for age
* calculations)
* @param version
* HTTP Response Version
* @param statusLine
* HTTP status line
* @param responseHeaders
* Header[] from original HTTP Response
* @param body
* HttpEntity representing the body of the response
* @param status
* Numeric HTTP Status Code
* @param reason
* String message from HTTP Status Line
*/
public HttpCacheEntry(
final Date requestDate,
final Date responseDate,
final StatusLine statusLine,
final Header[] responseHeaders,
final HttpEntity body,
final Set<String> variants) {
super();
if (requestDate == null) {
@ -103,17 +95,12 @@ public abstract class HttpCacheEntry implements Serializable {
if (responseHeaders == null) {
throw new IllegalArgumentException("Response headers may not be null");
}
if (body == null) {
throw new IllegalArgumentException("Response body may not be null");
}
this.requestDate = requestDate;
this.responseDate = responseDate;
this.statusLine = statusLine;
this.responseHeaders = new CachedHeaderGroup();
this.responseHeaders.setHeaders(responseHeaders);
this.body = body;
this.variantURIs = variants != null ? new HashSet<String>(variants) : new HashSet<String>();
}
public StatusLine getStatusLine() {
@ -140,10 +127,6 @@ public abstract class HttpCacheEntry implements Serializable {
return responseDate;
}
public HttpEntity getBody() {
return body;
}
public Header[] getAllHeaders() {
return responseHeaders.getAllHeaders();
}
@ -164,6 +147,12 @@ public abstract class HttpCacheEntry implements Serializable {
return Collections.unmodifiableSet(this.variantURIs);
}
public abstract Resource getResource();
public abstract InputStream getBody();
public abstract long getBodyLength();
private void writeObject(ObjectOutputStream out) throws IOException {
// write CacheEntry
@ -201,8 +190,6 @@ public abstract class HttpCacheEntry implements Serializable {
this.responseHeaders.setHeaders(headers);
}
public abstract Resource getResource();
@Override
public String toString() {
return "[request date=" + this.requestDate + "; response date=" + this.responseDate

View File

@ -26,11 +26,12 @@
*/
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.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.annotation.Immutable;
import org.apache.http.client.cache.HttpCacheEntry;
@ -45,14 +46,27 @@ public class BasicHttpCacheEntry extends HttpCacheEntry {
private static final long serialVersionUID = -8464486112875881235L;
private final byte[] body;
public BasicHttpCacheEntry(
final Date requestDate,
final Date responseDate,
final StatusLine statusLine,
final Header[] responseHeaders,
final HttpEntity body,
final byte[] body,
final Set<String> variants) {
super(requestDate, responseDate, statusLine, responseHeaders, body, variants);
super(requestDate, responseDate, statusLine, responseHeaders, variants);
this.body = body;
}
@Override
public long getBodyLength() {
return this.body.length;
}
@Override
public InputStream getBody() {
return new ByteArrayInputStream(this.body);
}
@Override

View File

@ -26,7 +26,6 @@
*/
package org.apache.http.impl.client.cache;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -35,43 +34,27 @@ import java.io.Serializable;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.annotation.Immutable;
import org.apache.http.message.BasicHeader;
import org.apache.http.client.cache.HttpCacheEntry;
import org.apache.http.protocol.HTTP;
@Immutable
class CacheEntity implements HttpEntity, Cloneable, Serializable {
class CacheEntity implements HttpEntity, Serializable {
private static final long serialVersionUID = -3467082284120936233L;
private final byte[] content;
private final String contentType;
private final String contentEncoding;
private final HttpCacheEntry cacheEntry;
public CacheEntity(final byte[] b, final String contentType, final String contentEncoding) {
public CacheEntity(final HttpCacheEntry cacheEntry) {
super();
this.content = b;
this.contentType = contentType;
this.contentEncoding = contentEncoding;
}
public CacheEntity(final byte[] b) {
this(b, null, null);
this.cacheEntry = cacheEntry;
}
public Header getContentType() {
if (this.contentType == null) {
return null;
}
return new BasicHeader(HTTP.CONTENT_TYPE, this.contentType);
return this.cacheEntry.getFirstHeader(HTTP.CONTENT_TYPE);
}
public Header getContentEncoding() {
if (this.contentEncoding == null) {
return null;
}
return new BasicHeader(HTTP.CONTENT_ENCODING, this.contentEncoding);
return this.cacheEntry.getFirstHeader(HTTP.CONTENT_ENCODING);
}
public boolean isChunked() {
@ -83,19 +66,23 @@ class CacheEntity implements HttpEntity, Cloneable, Serializable {
}
public long getContentLength() {
return this.content.length;
return this.cacheEntry.getBodyLength();
}
public InputStream getContent() {
return new ByteArrayInputStream(this.content);
return this.cacheEntry.getBody();
}
public void writeTo(final OutputStream outstream) throws IOException {
if (outstream == null) {
throw new IllegalArgumentException("Output stream may not be null");
}
outstream.write(this.content);
outstream.flush();
InputStream instream = this.cacheEntry.getBody();
byte[] buf = new byte[2048];
int len;
while ((len = instream.read(buf)) != -1) {
outstream.write(buf, 0, len);
}
}
public boolean isStreaming() {

View File

@ -26,15 +26,16 @@
*/
package org.apache.http.impl.client.cache;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.annotation.Immutable;
import org.apache.http.client.cache.HttpCacheEntry;
import org.apache.http.protocol.HTTP;
/**
* Generates a {@link CacheEntry} from a {@link HttpResponse}
@ -49,29 +50,32 @@ class CacheEntryGenerator {
Date responseDate,
HttpResponse response,
byte[] body) {
Header ct = response.getFirstHeader(HTTP.CONTENT_TYPE);
Header ce = response.getFirstHeader(HTTP.CONTENT_ENCODING);
CacheEntity entity = new CacheEntity(
body,
ct != null ? ct.getValue() : null,
ce != null ? ce.getValue() : null);
return new BasicHttpCacheEntry(requestDate,
responseDate,
response.getStatusLine(),
response.getAllHeaders(),
entity,
body,
null);
}
public HttpCacheEntry copyWithVariant(final HttpCacheEntry entry, final String variantURI){
public HttpCacheEntry copyWithVariant(
final HttpCacheEntry entry, final String variantURI) throws IOException {
Set<String> variants = new HashSet<String>(entry.getVariantURIs());
variants.add(variantURI);
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
InputStream instream = entry.getBody();
byte[] buf = new byte[2048];
int len;
while ((len = instream.read(buf)) != -1) {
outstream.write(buf, 0, len);
}
return new BasicHttpCacheEntry(
entry.getRequestDate(),
entry.getResponseDate(),
entry.getStatusLine(),
entry.getAllHeaders(),
entry.getBody(), variants);
outstream.toByteArray(),
variants);
}
}

View File

@ -26,7 +26,9 @@
*/
package org.apache.http.impl.client.cache;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@ -69,10 +71,17 @@ class CacheEntryUpdater {
HttpResponse response) throws IOException {
Header[] mergedHeaders = mergeHeaders(entry, response);
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
InputStream instream = entry.getBody();
byte[] buf = new byte[2048];
int len;
while ((len = instream.read(buf)) != -1) {
outstream.write(buf, 0, len);
}
HttpCacheEntry updated = new BasicHttpCacheEntry(requestDate, responseDate,
entry.getStatusLine(),
mergedHeaders,
entry.getBody(),
outstream.toByteArray(),
null);
return updated;
}

View File

@ -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.getBody().getContentLength();
return getContentLengthValue(entry) == entry.getBodyLength();
}
protected long getApparentAgeSecs(final HttpCacheEntry entry) {

View File

@ -70,10 +70,10 @@ class CachedHttpResponseGenerator {
.getStatusCode(), entry.getReasonPhrase());
if (entry.getStatusCode() != HttpStatus.SC_NOT_MODIFIED) {
HttpEntity entity = entry.getBody();
response.setEntity(entity);
HttpEntity entity = new CacheEntity(entry);
response.setHeaders(entry.getAllHeaders());
addMissingContentLengthHeader(response, entity);
response.setEntity(entity);
}
long age = this.validityStrategy.getCurrentAgeSecs(entry);

View File

@ -519,7 +519,7 @@ public class CachingHttpClient implements HttpClient {
HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
public HttpCacheEntry update(HttpCacheEntry existing) {
public HttpCacheEntry update(HttpCacheEntry existing) throws IOException {
return doGetUpdatedParentEntry(existing, entry, variantURI);
}
@ -530,7 +530,7 @@ public class CachingHttpClient implements HttpClient {
HttpCacheEntry doGetUpdatedParentEntry(
HttpCacheEntry existing,
HttpCacheEntry entry, String variantURI) {
HttpCacheEntry entry, String variantURI) throws IOException {
if (existing != null) {
return cacheEntryGenerator.copyWithVariant(existing, variantURI);
} else {

View File

@ -29,8 +29,6 @@ package org.apache.http.impl.client.cache;
import java.util.Date;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
public class CacheEntry extends BasicHttpCacheEntry {
@ -38,28 +36,17 @@ public class CacheEntry extends BasicHttpCacheEntry {
public static final long MAX_AGE = CacheValidityPolicy.MAX_AGE;
public CacheEntry(
Date requestDate,
Date responseDate,
StatusLine statusLine,
Header[] responseHeaders,
HttpEntity body) {
super(requestDate, responseDate, statusLine, responseHeaders, body, null);
}
public CacheEntry(
Date requestDate,
Date responseDate) {
super(requestDate, responseDate, new OKStatus(), new Header[] {},
new CacheEntity(new byte[] {}), null);
super(requestDate, responseDate, new OKStatus(), new Header[] {}, new byte[] {}, null);
}
public CacheEntry(
Date requestDate,
Date responseDate,
Header[] headers) {
super(requestDate, responseDate, new OKStatus(), headers,
new CacheEntity(new byte[] {}), null);
super(requestDate, responseDate, new OKStatus(), headers, new byte[] {}, null);
}
public CacheEntry(
@ -67,20 +54,17 @@ public class CacheEntry extends BasicHttpCacheEntry {
Date responseDate,
Header[] headers,
byte[] content) {
super(requestDate, responseDate, new OKStatus(), headers,
new CacheEntity(content), null);
super(requestDate, responseDate, new OKStatus(), headers, content, null);
}
public CacheEntry(
Header[] headers,
byte[] content) {
super(new Date(), new Date(), new OKStatus(), headers,
new CacheEntity(content), null);
super(new Date(), new Date(), new OKStatus(), headers, content, null);
}
public CacheEntry(Header[] headers) {
super(new Date(), new Date(), new OKStatus(), headers,
new CacheEntity(new byte[] {}), null);
super(new Date(), new Date(), new OKStatus(), headers, new byte[] {}, null);
}
public CacheEntry() {
@ -88,8 +72,7 @@ public class CacheEntry extends BasicHttpCacheEntry {
}
public CacheEntry(byte[] content) {
super(new Date(), new Date(), new OKStatus(), new Header[] {},
new CacheEntity(content), null);
super(new Date(), new Date(), new OKStatus(), new Header[] {}, content, null);
}
}

View File

@ -103,7 +103,7 @@ public class TestCacheEntry {
}
@Test
public void testCacheEntryCanStoreMultipleVariantUris() {
public void testCacheEntryCanStoreMultipleVariantUris() throws Exception {
Header[] headers = new Header[]{};
CacheEntry entry = new CacheEntry(headers);

View File

@ -1220,7 +1220,7 @@ public class TestCachingHttpClient {
bytes)).andReturn(mockCacheEntry);
}
private void copyCacheEntry(CacheEntry entry, String variantURI) {
private void copyCacheEntry(CacheEntry entry, String variantURI) throws IOException {
EasyMock.expect(
mockEntryGenerator.copyWithVariant(entry, variantURI)).andReturn(entry);
}

View File

@ -27,6 +27,7 @@
package org.apache.http.impl.client.cache;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import org.apache.http.client.cache.HttpCacheEntry;
import org.apache.http.client.cache.HttpCacheUpdateCallback;
@ -148,7 +149,7 @@ public class TestResponseCache {
existing.getRequestDate(),
existing.getStatusLine(),
existing.getAllHeaders(),
new CacheEntity(expectedArray),
expectedArray,
null);
return updated;
}
@ -156,9 +157,14 @@ public class TestResponseCache {
HttpCacheEntry afterUpdate = cache.getEntry("foo");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
afterUpdate.getBody().writeTo(stream);
byte[] bytes = stream.toByteArray();
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
InputStream instream = afterUpdate.getBody();
byte[] buf = new byte[2048];
int len;
while ((len = instream.read(buf)) != -1) {
outstream.write(buf, 0, len);
}
byte[] bytes = outstream.toByteArray();
Assert.assertArrayEquals(expectedArray, bytes);
}

View File

@ -632,10 +632,16 @@ public abstract class AbstractHttpClient implements HttpClient {
URI requestURI = request.getURI();
if (requestURI.isAbsolute()) {
String host = requestURI.getHost();
String ssp = requestURI.getSchemeSpecificPart();
ssp = ssp.substring(2, ssp.length()); //remove "//" prefix
int end = ssp.indexOf(':') > 0 ? ssp.indexOf(':') :
ssp.indexOf('/') > 0 ? ssp.indexOf('/') :
ssp.indexOf('?') > 0 ? ssp.indexOf('?') : ssp.length();
String host = ssp.substring(0, end);
int port = requestURI.getPort();
String scheme = requestURI.getScheme();
if (host == null) {
if (host == null || "".equals(host)) {
throw new ClientProtocolException(
"URI does not specify a valid host name: " + requestURI);
}

View File

@ -37,11 +37,11 @@ import org.apache.http.client.HttpClient;
import org.apache.http.client.UserTokenHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.localserver.ServerTestBase;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.ExecutionContext;
@ -83,7 +83,7 @@ public class TestStatefulConnManagement extends ServerTestBase {
HttpHost target = new HttpHost("localhost", port);
HttpParams params = new BasicHttpParams();
ConnManagerParams.setTimeout(params, 10L);
HttpConnectionParams.setConnectionTimeout(params, 10);
ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(supportedSchemes);
mgr.setMaxTotal(workerCount);