[prev in list] [next in list] [prev in thread] [next in thread] 

List:       httpcomponents-commits
Subject:    svn commit: r1051865 - in
From:       jonm () apache ! org
Date:       2010-12-22 11:59:23
Message-ID: 20101222115923.D4C652388994 () eris ! apache ! org
[Download RAW message or body]

Author: jonm
Date: Wed Dec 22 11:59:23 2010
New Revision: 1051865

URL: http://svn.apache.org/viewvc?rev=1051865&view=rev
Log:
HTTPCLIENT-1035: begin adding functionality for flushing updated
entries mentioned by Content-Location in responses. Not yet hooked
in to be used.

Modified:
    httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java
  httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java


Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java
                
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src \
/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java?rev=1051865&r1=1051864&r2=1051865&view=diff
 ==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java \
                (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java \
Wed Dec 22 11:59:23 2010 @@ -29,16 +29,20 @@ package org.apache.http.impl.client.cach
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Date;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.http.Header;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
 import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.client.cache.HeaderConstants;
 import org.apache.http.client.cache.HttpCacheEntry;
 import org.apache.http.client.cache.HttpCacheStorage;
+import org.apache.http.impl.cookie.DateParseException;
+import org.apache.http.impl.cookie.DateUtils;
 
 /**
  * Given a particular HttpRequest, flush any cache entries that this request
@@ -150,4 +154,45 @@ class CacheInvalidator {
         return !(HeaderConstants.GET_METHOD.equals(method) || \
                HeaderConstants.HEAD_METHOD
                 .equals(method));
     }
+
+    /** Flushes entries that were invalidated by the given response
+     * received for the given host/request pair. 
+     * @throws IOException 
+     */
+    public void flushInvalidatedCacheEntries(HttpHost host,
+            HttpRequest request, HttpResponse response) throws IOException {
+        Header contentLocation = response.getFirstHeader("Content-Location");
+        if (contentLocation == null) return;
+        HttpCacheEntry entry = storage.getEntry(contentLocation.getValue());
+        if (entry == null) return;
+
+        if (!responseDateNewerThanEntryDate(response, entry)) return;
+        if (!responseAndEntryEtagsDiffer(response, entry)) return;
+        
+        storage.removeEntry(contentLocation.getValue());
+    }
+
+    private boolean responseAndEntryEtagsDiffer(HttpResponse response,
+            HttpCacheEntry entry) {
+        Header entryEtag = entry.getFirstHeader("ETag");
+        Header responseEtag = response.getFirstHeader("ETag");
+        if (entryEtag == null || responseEtag == null) return false;
+        return (!entryEtag.getValue().equals(responseEtag.getValue()));
+    }
+
+    private boolean responseDateNewerThanEntryDate(HttpResponse response,
+            HttpCacheEntry entry) {
+        Header entryDateHeader = entry.getFirstHeader("Date");
+        Header responseDateHeader = response.getFirstHeader("Date");
+        if (entryDateHeader == null || responseDateHeader == null) {
+            return false;
+        }
+        try {
+            Date entryDate = DateUtils.parseDate(entryDateHeader.getValue());
+            Date responseDate = DateUtils.parseDate(responseDateHeader.getValue());
+            return responseDate.after(entryDate);
+        } catch (DateParseException e) {
+            return false;
+        }
+    }
 }

Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java
                
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src \
/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java?rev=1051865&r1=1051864&r2=1051865&view=diff
 ==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java \
                (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java \
Wed Dec 22 11:59:23 2010 @@ -27,17 +27,24 @@
 package org.apache.http.impl.client.cache;
 
 import java.io.IOException;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
+
+import org.apache.http.Header;
 import org.apache.http.HttpEntityEnclosingRequest;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
 import org.apache.http.ProtocolVersion;
 import org.apache.http.client.cache.HttpCacheEntry;
 import org.apache.http.client.cache.HttpCacheStorage;
+import static org.apache.http.impl.cookie.DateUtils.formatDate;
+
+import org.apache.http.message.BasicHeader;
 import org.apache.http.message.BasicHttpEntityEnclosingRequest;
 import org.apache.http.message.BasicHttpRequest;
-import org.easymock.classextension.EasyMock;
+import static org.easymock.classextension.EasyMock.*;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -48,34 +55,42 @@ public class TestCacheInvalidator {
     private CacheInvalidator impl;
     private HttpCacheStorage mockStorage;
     private HttpHost host;
-    private CacheKeyGenerator extractor;
+    private CacheKeyGenerator cacheKeyGenerator;
     private HttpCacheEntry mockEntry;
+    private HttpRequest request;
+    private HttpResponse response;
+
+    private Date now;
+    private Date tenSecondsAgo;
 
     @Before
     public void setUp() {
+        now = new Date();
+        tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+        
         host = new HttpHost("foo.example.com");
-        mockStorage = EasyMock.createMock(HttpCacheStorage.class);
-        extractor = new CacheKeyGenerator();
-        mockEntry = EasyMock.createMock(HttpCacheEntry.class);
+        mockStorage = createMock(HttpCacheStorage.class);
+        cacheKeyGenerator = new CacheKeyGenerator();
+        mockEntry = createMock(HttpCacheEntry.class);
+        response = HttpTestUtils.make200Response();
 
-        impl = new CacheInvalidator(extractor, mockStorage);
+        impl = new CacheInvalidator(cacheKeyGenerator, mockStorage);
     }
 
     private void replayMocks() {
-        EasyMock.replay(mockStorage);
-        EasyMock.replay(mockEntry);
+        replay(mockStorage);
+        replay(mockEntry);
     }
 
     private void verifyMocks() {
-        EasyMock.verify(mockStorage);
-        EasyMock.verify(mockEntry);
+        verify(mockStorage);
+        verify(mockEntry);
     }
 
     // Tests
     @Test
     public void testInvalidatesRequestsThatArentGETorHEAD() throws Exception {
-        HttpRequest request = new BasicHttpRequest("POST","/path", HTTP_1_1);
-
+        request = new BasicHttpRequest("POST","/path", HTTP_1_1);
         final String theUri = "http://foo.example.com:80/path";
         Map<String,String> variantMap = new HashMap<String,String>();
         cacheEntryHasVariantMap(variantMap);
@@ -126,7 +141,7 @@ public class TestCacheInvalidator {
 
         cacheReturnsEntryForUri(theUri);
         entryIsRemoved(theUri);
-        entryIsRemoved(extractor.canonicalizeUri(contentLocation));
+        entryIsRemoved(cacheKeyGenerator.canonicalizeUri(contentLocation));
 
         replayMocks();
 
@@ -182,54 +197,41 @@ public class TestCacheInvalidator {
 
     @Test
     public void testDoesNotInvalidateGETRequest() throws Exception {
-        HttpRequest request = new BasicHttpRequest("GET","/",HTTP_1_1);
-
+        request = new BasicHttpRequest("GET","/",HTTP_1_1);
         replayMocks();
-
         impl.flushInvalidatedCacheEntries(host, request);
-
         verifyMocks();
     }
 
     @Test
     public void testDoesNotInvalidateHEADRequest() throws Exception {
-        HttpRequest request = new BasicHttpRequest("HEAD","/",HTTP_1_1);
-
+        request = new BasicHttpRequest("HEAD","/",HTTP_1_1);
         replayMocks();
-
         impl.flushInvalidatedCacheEntries(host, request);
-
         verifyMocks();
     }
 
     @Test
     public void testDoesNotInvalidateRequestsWithClientCacheControlHeaders() throws \
                Exception {
-        HttpRequest request = new BasicHttpRequest("GET","/",HTTP_1_1);
+        request = new BasicHttpRequest("GET","/",HTTP_1_1);
         request.setHeader("Cache-Control","no-cache");
-
         replayMocks();
-
         impl.flushInvalidatedCacheEntries(host, request);
-
         verifyMocks();
     }
 
     @Test
     public void testDoesNotInvalidateRequestsWithClientPragmaHeaders() throws \
                Exception {
-        HttpRequest request = new BasicHttpRequest("GET","/",HTTP_1_1);
+        request = new BasicHttpRequest("GET","/",HTTP_1_1);
         request.setHeader("Pragma","no-cache");
-
         replayMocks();
-
         impl.flushInvalidatedCacheEntries(host, request);
-
         verifyMocks();
     }
 
     @Test
     public void testVariantURIsAreFlushedAlso() throws Exception {
-        HttpRequest request = new BasicHttpRequest("POST","/",HTTP_1_1);
-
+        request = new BasicHttpRequest("POST","/",HTTP_1_1);
         final String theUri = "http://foo.example.com:80/";
         final String variantUri = "theVariantURI";
 
@@ -249,7 +251,7 @@ public class TestCacheInvalidator {
 
     @Test(expected=IOException.class)
     public void testCacheFlushException() throws Exception {
-        HttpRequest request = new BasicHttpRequest("POST","/",HTTP_1_1);
+        request = new BasicHttpRequest("POST","/",HTTP_1_1);
         String theURI = "http://foo.example.com:80/";
 
         cacheReturnsExceptionForUri(theURI);
@@ -257,18 +259,182 @@ public class TestCacheInvalidator {
         replayMocks();
         impl.flushInvalidatedCacheEntries(host, request);
     }
+    
+    @Test
+    public void doesNotFlushForResponsesWithoutContentLocation()
+            throws Exception {
+        request = HttpTestUtils.makeDefaultRequest();
+        replayMocks();
+        impl.flushInvalidatedCacheEntries(host, request, response);
+        verifyMocks();
+    }
+    
+    @Test
+    public void flushesEntryIfFresherAndSpecifiedByContentLocation()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", formatDate(now));
+        String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+        
+        HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", formatDate(tenSecondsAgo)),
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+        
+        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
+        mockStorage.removeEntry(theURI);
+        
+        replayMocks();
+        impl.flushInvalidatedCacheEntries(host, request, response);
+        verifyMocks();
+    }
+
+    @Test
+    public void doesNotFlushEntrySpecifiedByContentLocationIfEtagsMatch()
+            throws Exception {
+        response.setHeader("ETag","\"same-etag\"");
+        response.setHeader("Date", formatDate(now));
+        String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+        
+        HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", formatDate(tenSecondsAgo)),
+           new BasicHeader("ETag", "\"same-etag\"")
+        });
+        
+        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
+        
+        replayMocks();
+        impl.flushInvalidatedCacheEntries(host, request, response);
+        verifyMocks();
+    }
+
+    @Test
+    public void doesNotFlushEntrySpecifiedByContentLocationIfNotNewer()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", formatDate(now));
+        String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+        
+        HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", formatDate(now)),
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+        
+        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
+        
+        replayMocks();
+        impl.flushInvalidatedCacheEntries(host, request, response);
+        verifyMocks();
+    }
+    
+    @Test
+    public void doesNotFlushEntryIfNotInCache()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", formatDate(now));
+        String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+        
+        expect(mockStorage.getEntry(theURI)).andReturn(null).anyTimes();
+        
+        replayMocks();
+        impl.flushInvalidatedCacheEntries(host, request, response);
+        verifyMocks();
+    }
+    
+    @Test
+    public void doesNotFlushEntrySpecifiedByContentLocationIfResponseHasNoEtag()
+            throws Exception {
+        response.removeHeaders("ETag");
+        response.setHeader("Date", formatDate(now));
+        String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+        
+        HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", formatDate(tenSecondsAgo)),
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+        
+        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
+        
+        replayMocks();
+        impl.flushInvalidatedCacheEntries(host, request, response);
+        verifyMocks();
+    }
+    
+    @Test
+    public void doesNotFlushEntrySpecifiedByContentLocationIfEntryHasNoEtag()
+            throws Exception {
+        response.setHeader("ETag", "\"some-etag\"");
+        response.setHeader("Date", formatDate(now));
+        String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+        
+        HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("Date", formatDate(tenSecondsAgo)),
+        });
+        
+        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
+        
+        replayMocks();
+        impl.flushInvalidatedCacheEntries(host, request, response);
+        verifyMocks();
+    }
+
+    @Test
+    public void doesNotFlushEntrySpecifiedByContentLocationIfResponseHasNoDate()
+            throws Exception {
+        response.setHeader("ETag", "\"new-etag\"");
+        response.removeHeaders("Date");
+        String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+        
+        HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+                new BasicHeader("ETag", "\"old-etag\""),
+                new BasicHeader("Date", formatDate(tenSecondsAgo)),
+        });
+        
+        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
+        
+        replayMocks();
+        impl.flushInvalidatedCacheEntries(host, request, response);
+        verifyMocks();
+    }
+    
+    @Test
+    public void doesNotFlushEntrySpecifiedByContentLocationIfEntryHasNoDate()
+            throws Exception {
+        response.setHeader("ETag","\"new-etag\"");
+        response.setHeader("Date", formatDate(now));
+        String theURI = "http://foo.example.com:80/bar";
+        response.setHeader("Content-Location", theURI);
+        
+        HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
+           new BasicHeader("ETag", "\"old-etag\"")
+        });
+        
+        expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes();
+        
+        replayMocks();
+        impl.flushInvalidatedCacheEntries(host, request, response);
+        verifyMocks();
+    }
 
+    
     // Expectations
     private void cacheEntryHasVariantMap(Map<String,String> variantMap) {
-        org.easymock.EasyMock.expect(mockEntry.getVariantMap()).andReturn(variantMap);
 +        expect(mockEntry.getVariantMap()).andReturn(variantMap);
     }
 
     private void cacheReturnsEntryForUri(String theUri) throws IOException {
-        org.easymock.EasyMock.expect(mockStorage.getEntry(theUri)).andReturn(mockEntry);
 +        expect(mockStorage.getEntry(theUri)).andReturn(mockEntry);
     }
 
     private void cacheReturnsExceptionForUri(String theUri) throws IOException {
-        org.easymock.EasyMock.expect(mockStorage.getEntry(theUri)).andThrow(
+        expect(mockStorage.getEntry(theUri)).andThrow(
                 new IOException("TOTAL FAIL"));
     }
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic