You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by mi...@apache.org on 2020/01/10 10:02:05 UTC

[httpcomponents-client] 01/01: HTTPCLIENT-2036: CacheValidityPolicy should use TimeValue

This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a commit to branch HTTPCLIENT-2036
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit 26991b80597e7d4206f0d603b772559b254dc4ae
Author: Michael Osipov <mi...@apache.org>
AuthorDate: Sun Dec 15 13:33:11 2019 +0100

    HTTPCLIENT-2036: CacheValidityPolicy should use TimeValue
    
    This closes #201
---
 .../http/impl/cache/CacheValidityPolicy.java       |  92 ++++++++++---------
 .../impl/cache/CachedHttpResponseGenerator.java    |  11 +--
 .../cache/CachedResponseSuitabilityChecker.java    |  18 ++--
 .../client5/http/impl/cache/CachingExecBase.java   |  10 ++-
 .../cache/HttpByteArrayCacheEntrySerializer.java   |   7 +-
 .../http/impl/cache/TestCacheValidityPolicy.java   | 100 +++++++++++----------
 .../cache/TestCachedHttpResponseGenerator.java     |  21 ++---
 .../http/impl/cache/TestCachingExecChain.java      |  11 +--
 8 files changed, 145 insertions(+), 125 deletions(-)

diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java
index 7f7a674..ef2b82c 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java
@@ -39,46 +39,48 @@ import org.apache.hc.core5.http.HttpHeaders;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.MessageHeaders;
 import org.apache.hc.core5.http.message.MessageSupport;
+import org.apache.hc.core5.util.TimeValue;
 
 class CacheValidityPolicy {
 
-    public static final long MAX_AGE = 2147483648L;
+    public static final TimeValue MAX_AGE = TimeValue.ofSeconds(Integer.MAX_VALUE + 1L);
 
     CacheValidityPolicy() {
         super();
     }
 
-    public long getCurrentAgeSecs(final HttpCacheEntry entry, final Date now) {
-        return getCorrectedInitialAgeSecs(entry) + getResidentTimeSecs(entry, now);
+    public TimeValue getCurrentAge(final HttpCacheEntry entry, final Date now) {
+        return TimeValue.ofSeconds(getCorrectedInitialAge(entry).toSeconds() + getResidentTime(entry, now).toSeconds());
     }
 
-    public long getFreshnessLifetimeSecs(final HttpCacheEntry entry) {
+    public TimeValue getFreshnessLifetime(final HttpCacheEntry entry) {
         final long maxAge = getMaxAge(entry);
         if (maxAge > -1) {
-            return maxAge;
+            return TimeValue.ofSeconds(maxAge);
         }
 
         final Date dateValue = entry.getDate();
         if (dateValue == null) {
-            return 0L;
+            return TimeValue.ZERO_MILLISECONDS;
         }
 
         final Date expiry = DateUtils.parseDate(entry, HeaderConstants.EXPIRES);
         if (expiry == null) {
-            return 0;
+            return TimeValue.ZERO_MILLISECONDS;
         }
         final long diff = expiry.getTime() - dateValue.getTime();
-        return (diff / 1000);
+        return TimeValue.ofSeconds(diff / 1000);
     }
 
     public boolean isResponseFresh(final HttpCacheEntry entry, final Date now) {
-        return (getCurrentAgeSecs(entry, now) < getFreshnessLifetimeSecs(entry));
+        return getCurrentAge(entry, now).compareTo(getFreshnessLifetime(entry)) == -1;
     }
 
     /**
      * Decides if this response is fresh enough based Last-Modified and Date, if available.
-     * This entry is meant to be used when isResponseFresh returns false.  The algorithm is as follows:
+     * This entry is meant to be used when isResponseFresh returns false.
      *
+     * The algorithm is as follows:
      * if last-modified and date are defined, freshness lifetime is coefficient*(date-lastModified),
      * else freshness lifetime is defaultLifetime
      *
@@ -89,21 +91,21 @@ class CacheValidityPolicy {
      * @return {@code true} if the response is fresh
      */
     public boolean isResponseHeuristicallyFresh(final HttpCacheEntry entry,
-            final Date now, final float coefficient, final long defaultLifetime) {
-        return (getCurrentAgeSecs(entry, now) < getHeuristicFreshnessLifetimeSecs(entry, coefficient, defaultLifetime));
+            final Date now, final float coefficient, final TimeValue defaultLifetime) {
+        return getCurrentAge(entry, now).compareTo(getHeuristicFreshnessLifetime(entry, coefficient, defaultLifetime)) == -1;
     }
 
-    public long getHeuristicFreshnessLifetimeSecs(final HttpCacheEntry entry,
-            final float coefficient, final long defaultLifetime) {
+    public TimeValue getHeuristicFreshnessLifetime(final HttpCacheEntry entry,
+            final float coefficient, final TimeValue defaultLifetime) {
         final Date dateValue = entry.getDate();
         final Date lastModifiedValue = DateUtils.parseDate(entry, HeaderConstants.LAST_MODIFIED);
 
         if (dateValue != null && lastModifiedValue != null) {
             final long diff = dateValue.getTime() - lastModifiedValue.getTime();
             if (diff < 0) {
-                return 0;
+                return TimeValue.ZERO_MILLISECONDS;
             }
-            return (long)(coefficient * (diff / 1000));
+            return TimeValue.ofSeconds((long) (coefficient * diff / 1000));
         }
 
         return defaultLifetime;
@@ -128,8 +130,9 @@ class CacheValidityPolicy {
             final HeaderElement elt = it.next();
             if (HeaderConstants.STALE_WHILE_REVALIDATE.equalsIgnoreCase(elt.getName())) {
                 try {
+                    // in seconds
                     final int allowedStalenessLifetime = Integer.parseInt(elt.getValue());
-                    if (getStalenessSecs(entry, now) <= allowedStalenessLifetime) {
+                    if (getStaleness(entry, now).compareTo(TimeValue.ofSeconds(allowedStalenessLifetime)) <= 0) {
                         return true;
                     }
                 } catch (final NumberFormatException nfe) {
@@ -142,20 +145,21 @@ class CacheValidityPolicy {
     }
 
     public boolean mayReturnStaleIfError(final HttpRequest request, final HttpCacheEntry entry, final Date now) {
-        final long stalenessSecs = getStalenessSecs(entry, now);
-        return mayReturnStaleIfError(request, HeaderConstants.CACHE_CONTROL, stalenessSecs)
-                || mayReturnStaleIfError(entry, HeaderConstants.CACHE_CONTROL, stalenessSecs);
+        final TimeValue staleness = getStaleness(entry, now);
+        return mayReturnStaleIfError(request, HeaderConstants.CACHE_CONTROL, staleness)
+                || mayReturnStaleIfError(entry, HeaderConstants.CACHE_CONTROL, staleness);
     }
 
-    private boolean mayReturnStaleIfError(final MessageHeaders headers, final String name, final long stalenessSecs) {
+    private boolean mayReturnStaleIfError(final MessageHeaders headers, final String name, final TimeValue staleness) {
         boolean result = false;
         final Iterator<HeaderElement> it = MessageSupport.iterate(headers, name);
         while (it.hasNext()) {
             final HeaderElement elt = it.next();
             if (HeaderConstants.STALE_IF_ERROR.equals(elt.getName())) {
                 try {
-                    final int staleIfErrorSecs = Integer.parseInt(elt.getValue());
-                    if (stalenessSecs <= staleIfErrorSecs) {
+                    // in seconds
+                    final int staleIfError = Integer.parseInt(elt.getValue());
+                    if (staleness.compareTo(TimeValue.ofSeconds(staleIfError)) <= 0) {
                         result = true;
                         break;
                     }
@@ -192,56 +196,58 @@ class CacheValidityPolicy {
         return true;
     }
 
-    protected long getApparentAgeSecs(final HttpCacheEntry entry) {
+    protected TimeValue getApparentAge(final HttpCacheEntry entry) {
         final Date dateValue = entry.getDate();
         if (dateValue == null) {
             return MAX_AGE;
         }
         final long diff = entry.getResponseDate().getTime() - dateValue.getTime();
         if (diff < 0L) {
-            return 0;
+            return TimeValue.ZERO_MILLISECONDS;
         }
-        return (diff / 1000);
+        return TimeValue.ofSeconds(diff / 1000);
     }
 
     protected long getAgeValue(final HttpCacheEntry entry) {
+        // This is a header value, we leave as-is
         long ageValue = 0;
         for (final Header hdr : entry.getHeaders(HeaderConstants.AGE)) {
             long hdrAge;
             try {
                 hdrAge = Long.parseLong(hdr.getValue());
                 if (hdrAge < 0) {
-                    hdrAge = MAX_AGE;
+                    hdrAge = MAX_AGE.toSeconds();
                 }
             } catch (final NumberFormatException nfe) {
-                hdrAge = MAX_AGE;
+                hdrAge = MAX_AGE.toSeconds();
             }
             ageValue = (hdrAge > ageValue) ? hdrAge : ageValue;
         }
         return ageValue;
     }
 
-    protected long getCorrectedReceivedAgeSecs(final HttpCacheEntry entry) {
-        final long apparentAge = getApparentAgeSecs(entry);
+    protected TimeValue getCorrectedReceivedAge(final HttpCacheEntry entry) {
+        final TimeValue apparentAge = getApparentAge(entry);
         final long ageValue = getAgeValue(entry);
-        return (apparentAge > ageValue) ? apparentAge : ageValue;
+        return (apparentAge.toSeconds() > ageValue) ? apparentAge : TimeValue.ofSeconds(ageValue);
     }
 
-    protected long getResponseDelaySecs(final HttpCacheEntry entry) {
+    protected TimeValue getResponseDelay(final HttpCacheEntry entry) {
         final long diff = entry.getResponseDate().getTime() - entry.getRequestDate().getTime();
-        return (diff / 1000L);
+        return TimeValue.ofSeconds(diff / 1000);
     }
 
-    protected long getCorrectedInitialAgeSecs(final HttpCacheEntry entry) {
-        return getCorrectedReceivedAgeSecs(entry) + getResponseDelaySecs(entry);
+    protected TimeValue getCorrectedInitialAge(final HttpCacheEntry entry) {
+        return TimeValue.ofSeconds(getCorrectedReceivedAge(entry).toSeconds() + getResponseDelay(entry).toSeconds());
     }
 
-    protected long getResidentTimeSecs(final HttpCacheEntry entry, final Date now) {
+    protected TimeValue getResidentTime(final HttpCacheEntry entry, final Date now) {
         final long diff = now.getTime() - entry.getResponseDate().getTime();
-        return (diff / 1000L);
+        return TimeValue.ofSeconds(diff / 1000);
     }
 
     protected long getMaxAge(final HttpCacheEntry entry) {
+        // This is a header value, we leave as-is
         long maxAge = -1;
         final Iterator<HeaderElement> it = MessageSupport.iterate(entry, HeaderConstants.CACHE_CONTROL);
         while (it.hasNext()) {
@@ -272,13 +278,13 @@ class CacheValidityPolicy {
         return false;
     }
 
-    public long getStalenessSecs(final HttpCacheEntry entry, final Date now) {
-        final long age = getCurrentAgeSecs(entry, now);
-        final long freshness = getFreshnessLifetimeSecs(entry);
-        if (age <= freshness) {
-            return 0L;
+    public TimeValue getStaleness(final HttpCacheEntry entry, final Date now) {
+        final TimeValue age = getCurrentAge(entry, now);
+        final TimeValue freshness = getFreshnessLifetime(entry);
+        if (age.compareTo(freshness) <= 0) {
+            return TimeValue.ZERO_MILLISECONDS;
         }
-        return (age - freshness);
+        return TimeValue.ofSeconds(age.toSeconds() - freshness.toSeconds());
     }
 
 
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedHttpResponseGenerator.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedHttpResponseGenerator.java
index e291f6e..614ed0e 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedHttpResponseGenerator.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedHttpResponseGenerator.java
@@ -42,6 +42,7 @@ import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.HttpVersion;
 import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.util.TimeValue;
 
 /**
  * Rebuilds an {@link HttpResponse} from a {@link HttpCacheEntry}
@@ -78,12 +79,12 @@ class CachedHttpResponseGenerator {
             response.setBodyBytes(content, contentType);
         }
 
-        final long age = this.validityStrategy.getCurrentAgeSecs(entry, now);
-        if (age > 0) {
-            if (age >= Integer.MAX_VALUE) {
-                response.setHeader(HeaderConstants.AGE, "2147483648");
+        final TimeValue age = this.validityStrategy.getCurrentAge(entry, now);
+        if (TimeValue.isPositive(age)) {
+            if (age.compareTo(CacheValidityPolicy.MAX_AGE) >= 0) {
+                response.setHeader(HeaderConstants.AGE, "" + CacheValidityPolicy.MAX_AGE.toSeconds());
             } else {
-                response.setHeader(HeaderConstants.AGE, "" + ((int) age));
+                response.setHeader(HeaderConstants.AGE, "" + age.toSeconds());
             }
         }
 
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java
index eb5210e..f680b5a 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java
@@ -75,7 +75,7 @@ class CachedResponseSuitabilityChecker {
             return true;
         }
         if (useHeuristicCaching &&
-                validityStrategy.isResponseHeuristicallyFresh(entry, now, heuristicCoefficient, heuristicDefaultLifetime.toSeconds())) {
+                validityStrategy.isResponseHeuristicallyFresh(entry, now, heuristicCoefficient, heuristicDefaultLifetime)) {
             return true;
         }
         if (originInsistsOnFreshness(entry)) {
@@ -85,7 +85,7 @@ class CachedResponseSuitabilityChecker {
         if (maxStale == -1) {
             return false;
         }
-        return (maxStale > validityStrategy.getStalenessSecs(entry, now));
+        return (maxStale > validityStrategy.getStaleness(entry, now).toSeconds());
     }
 
     private boolean originInsistsOnFreshness(final HttpCacheEntry entry) {
@@ -100,6 +100,7 @@ class CachedResponseSuitabilityChecker {
     }
 
     private long getMaxStale(final HttpRequest request) {
+        // This is a header value, we leave as-is
         long maxStale = -1;
         final Iterator<HeaderElement> it = MessageSupport.iterate(request, HeaderConstants.CACHE_CONTROL);
         while (it.hasNext()) {
@@ -186,8 +187,9 @@ class CachedResponseSuitabilityChecker {
 
             if (HeaderConstants.CACHE_CONTROL_MAX_AGE.equals(elt.getName())) {
                 try {
+                    // in seconds
                     final int maxAge = Integer.parseInt(elt.getValue());
-                    if (validityStrategy.getCurrentAgeSecs(entry, now) > maxAge) {
+                    if (validityStrategy.getCurrentAge(entry, now).toSeconds() > maxAge) {
                         log.debug("Response from cache was not suitable due to max age");
                         return false;
                     }
@@ -200,8 +202,9 @@ class CachedResponseSuitabilityChecker {
 
             if (HeaderConstants.CACHE_CONTROL_MAX_STALE.equals(elt.getName())) {
                 try {
+                    // in seconds
                     final int maxStale = Integer.parseInt(elt.getValue());
-                    if (validityStrategy.getFreshnessLifetimeSecs(entry) > maxStale) {
+                    if (validityStrategy.getFreshnessLifetime(entry).toSeconds() > maxStale) {
                         log.debug("Response from cache was not suitable due to max stale freshness");
                         return false;
                     }
@@ -214,13 +217,14 @@ class CachedResponseSuitabilityChecker {
 
             if (HeaderConstants.CACHE_CONTROL_MIN_FRESH.equals(elt.getName())) {
                 try {
+                    // in seconds
                     final long minFresh = Long.parseLong(elt.getValue());
                     if (minFresh < 0L) {
                         return false;
                     }
-                    final long age = validityStrategy.getCurrentAgeSecs(entry, now);
-                    final long freshness = validityStrategy.getFreshnessLifetimeSecs(entry);
-                    if (freshness - age < minFresh) {
+                    final TimeValue age = validityStrategy.getCurrentAge(entry, now);
+                    final TimeValue freshness = validityStrategy.getFreshnessLifetime(entry);
+                    if (freshness.toSeconds() - age.toSeconds() < minFresh) {
                         log.debug("Response from cache was not suitable due to min fresh " +
                                 "freshness requirement");
                         return false;
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java
index cb7a421..e2ee72d 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java
@@ -54,6 +54,7 @@ import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.message.MessageSupport;
 import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.VersionInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -189,7 +190,7 @@ public class CachingExecBase {
             cachedResponse = responseGenerator.generateResponse(request, entry);
         }
         setResponseStatus(context, CacheResponseStatus.CACHE_HIT);
-        if (validityPolicy.getStalenessSecs(entry, now) > 0L) {
+        if (TimeValue.isPositive(validityPolicy.getStaleness(entry, now))) {
             cachedResponse.addHeader(HeaderConstants.WARNING,"110 localhost \"Response is stale\"");
         }
         return cachedResponse;
@@ -247,10 +248,11 @@ public class CachingExecBase {
             final HeaderElement elt = it.next();
             if (HeaderConstants.CACHE_CONTROL_MAX_STALE.equals(elt.getName())) {
                 try {
+                    // in seconds
                     final int maxStale = Integer.parseInt(elt.getValue());
-                    final long age = validityPolicy.getCurrentAgeSecs(entry, now);
-                    final long lifetime = validityPolicy.getFreshnessLifetimeSecs(entry);
-                    if (age - lifetime > maxStale) {
+                    final TimeValue age = validityPolicy.getCurrentAge(entry, now);
+                    final TimeValue lifetime = validityPolicy.getFreshnessLifetime(entry);
+                    if (age.toSeconds() - lifetime.toSeconds() > maxStale) {
                         return true;
                     }
                 } catch (final NumberFormatException nfe) {
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/HttpByteArrayCacheEntrySerializer.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/HttpByteArrayCacheEntrySerializer.java
index e5b8eb4..a2aa75d 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/HttpByteArrayCacheEntrySerializer.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/HttpByteArrayCacheEntrySerializer.java
@@ -61,6 +61,7 @@ import org.apache.hc.core5.http.message.BasicHttpRequest;
 import org.apache.hc.core5.http.message.BasicLineFormatter;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.util.CharArrayBuffer;
+import org.apache.hc.core5.util.TimeValue;
 
 /**
  * Cache serializer and deserializer that uses an HTTP-like format.
@@ -402,15 +403,15 @@ public class HttpByteArrayCacheEntrySerializer implements HttpCacheEntrySerializ
     }
 
     /**
-     * Cache validity policy that always returns an age of 0.
+     * Cache validity policy that always returns an age of {@link TimeValue#ZERO_MILLISECONDS}.
      *
      * This prevents the Age header from being written to the cache (it does not make sense to cache it),
      * and is the only thing the policy is used for in this case.
      */
     private static class NoAgeCacheValidityPolicy extends CacheValidityPolicy {
         @Override
-        public long getCurrentAgeSecs(final HttpCacheEntry entry, final Date now) {
-            return 0L;
+        public TimeValue getCurrentAge(final HttpCacheEntry entry, final Date now) {
+            return TimeValue.ZERO_MILLISECONDS;
         }
     }
 }
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java
index 4da26f7..2389644 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java
@@ -40,6 +40,7 @@ import org.apache.hc.core5.http.HttpHeaders;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
+import org.apache.hc.core5.util.TimeValue;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -68,7 +69,7 @@ public class TestCacheValidityPolicy {
                 new BasicHeader("Server", "MockServer/1.0")
         };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(2147483648L, impl.getApparentAgeSecs(entry));
+        assertEquals(CacheValidityPolicy.MAX_AGE, impl.getApparentAge(entry));
     }
 
     @Test
@@ -77,15 +78,15 @@ public class TestCacheValidityPolicy {
                 .formatDate(tenSecondsAgo)) };
 
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, sixSecondsAgo, headers);
-        assertEquals(4, impl.getApparentAgeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(4), impl.getApparentAge(entry));
     }
 
     @Test
     public void testNegativeApparentAgeIsBroughtUpToZero() {
         final Header[] headers = new Header[] { new BasicHeader("Date", DateUtils
                 .formatDate(sixSecondsAgo)) };
-        final HttpCacheEntry entry  = HttpTestUtils.makeCacheEntry(now,tenSecondsAgo,headers);
-        assertEquals(0, impl.getApparentAgeSecs(entry));
+        final HttpCacheEntry entry  = HttpTestUtils.makeCacheEntry(now, tenSecondsAgo, headers);
+        assertEquals(TimeValue.ofSeconds(0), impl.getApparentAge(entry));
     }
 
     @Test
@@ -94,11 +95,11 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
         impl = new CacheValidityPolicy() {
             @Override
-            protected long getApparentAgeSecs(final HttpCacheEntry ent) {
-                return 6;
+            protected TimeValue getApparentAge(final HttpCacheEntry ent) {
+                return TimeValue.ofSeconds(6);
             }
         };
-        assertEquals(10, impl.getCorrectedReceivedAgeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(10), impl.getCorrectedReceivedAge(entry));
     }
 
     @Test
@@ -107,17 +108,17 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
         impl = new CacheValidityPolicy() {
             @Override
-            protected long getApparentAgeSecs(final HttpCacheEntry ent) {
-                return 10;
+            protected TimeValue getApparentAge(final HttpCacheEntry ent) {
+                return TimeValue.ofSeconds(10);
             }
         };
-        assertEquals(10, impl.getCorrectedReceivedAgeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(10), impl.getCorrectedReceivedAge(entry));
     }
 
     @Test
     public void testResponseDelayIsDifferenceBetweenResponseAndRequestTimes() {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(tenSecondsAgo, sixSecondsAgo);
-        assertEquals(4, impl.getResponseDelaySecs(entry));
+        assertEquals(TimeValue.ofSeconds(4), impl.getResponseDelay(entry));
     }
 
     @Test
@@ -125,22 +126,22 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
         impl = new CacheValidityPolicy() {
             @Override
-            protected long getCorrectedReceivedAgeSecs(final HttpCacheEntry ent) {
-                return 7;
+            protected TimeValue getCorrectedReceivedAge(final HttpCacheEntry ent) {
+                return TimeValue.ofSeconds(7);
             }
 
             @Override
-            protected long getResponseDelaySecs(final HttpCacheEntry ent) {
-                return 13;
+            protected TimeValue getResponseDelay(final HttpCacheEntry ent) {
+                return TimeValue.ofSeconds(13);
             }
         };
-        assertEquals(20, impl.getCorrectedInitialAgeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(20), impl.getCorrectedInitialAge(entry));
     }
 
     @Test
     public void testResidentTimeSecondsIsTimeSinceResponseTime() {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, sixSecondsAgo);
-        assertEquals(6, impl.getResidentTimeSecs(entry, now));
+        assertEquals(TimeValue.ofSeconds(6), impl.getResidentTime(entry, now));
     }
 
     @Test
@@ -148,29 +149,29 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
         impl = new CacheValidityPolicy() {
             @Override
-            protected long getCorrectedInitialAgeSecs(final HttpCacheEntry ent) {
-                return 11;
+            protected TimeValue getCorrectedInitialAge(final HttpCacheEntry ent) {
+                return TimeValue.ofSeconds(11);
             }
             @Override
-            protected long getResidentTimeSecs(final HttpCacheEntry ent, final Date d) {
-                return 17;
+            protected TimeValue getResidentTime(final HttpCacheEntry ent, final Date d) {
+                return TimeValue.ofSeconds(17);
             }
         };
-        assertEquals(28, impl.getCurrentAgeSecs(entry, new Date()));
+        assertEquals(TimeValue.ofSeconds(28), impl.getCurrentAge(entry, new Date()));
     }
 
     @Test
     public void testFreshnessLifetimeIsSMaxAgeIfPresent() {
         final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "s-maxage=10") };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(10, impl.getFreshnessLifetimeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
     }
 
     @Test
     public void testFreshnessLifetimeIsMaxAgeIfPresent() {
         final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10") };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(10, impl.getFreshnessLifetimeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
     }
 
     @Test
@@ -178,12 +179,12 @@ public class TestCacheValidityPolicy {
         Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10"),
                 new BasicHeader("Cache-Control", "s-maxage=20") };
         HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(10, impl.getFreshnessLifetimeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
 
         headers = new Header[] { new BasicHeader("Cache-Control", "max-age=20"),
                 new BasicHeader("Cache-Control", "s-maxage=10") };
         entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(10, impl.getFreshnessLifetimeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
     }
 
     @Test
@@ -193,7 +194,7 @@ public class TestCacheValidityPolicy {
                 new BasicHeader("Expires", DateUtils.formatDate(sixSecondsAgo)) };
 
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(10, impl.getFreshnessLifetimeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
     }
 
     @Test
@@ -203,7 +204,7 @@ public class TestCacheValidityPolicy {
                 new BasicHeader("Expires", DateUtils.formatDate(sixSecondsAgo)) };
 
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(10, impl.getFreshnessLifetimeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(entry));
     }
 
     @Test
@@ -213,7 +214,7 @@ public class TestCacheValidityPolicy {
                 new BasicHeader("Expires", DateUtils.formatDate(sixSecondsAgo)) };
 
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(4, impl.getFreshnessLifetimeSecs(entry));
+        assertEquals(TimeValue.ofSeconds(4), impl.getFreshnessLifetime(entry));
     }
 
     @Test
@@ -223,14 +224,14 @@ public class TestCacheValidityPolicy {
                 new BasicHeader("Last-Modified", DateUtils.formatDate(elevenSecondsAgo))
         };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(1, impl.getHeuristicFreshnessLifetimeSecs(entry, 0.1f, 0));
+        assertEquals(TimeValue.ofSeconds(1), impl.getHeuristicFreshnessLifetime(entry, 0.1f, TimeValue.ZERO_MILLISECONDS));
     }
 
     @Test
     public void testHeuristicFreshnessLifetimeDefaultsProperly() {
-        final long defaultFreshness = 10;
+        final TimeValue defaultFreshness = TimeValue.ofSeconds(10);
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
-        assertEquals(defaultFreshness, impl.getHeuristicFreshnessLifetimeSecs(entry, 0.1f, defaultFreshness));
+        assertEquals(defaultFreshness, impl.getHeuristicFreshnessLifetime(entry, 0.1f, defaultFreshness));
     }
 
     @Test
@@ -241,7 +242,7 @@ public class TestCacheValidityPolicy {
         };
 
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertTrue(impl.getHeuristicFreshnessLifetimeSecs(entry, 0.1f, 10) >= 0);
+        assertTrue(TimeValue.isNonNegative(impl.getHeuristicFreshnessLifetime(entry, 0.1f, TimeValue.ofSeconds(10))));
     }
 
     @Test
@@ -249,15 +250,15 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
         impl = new CacheValidityPolicy() {
             @Override
-            public long getCurrentAgeSecs(final HttpCacheEntry e, final Date d) {
+            public TimeValue getCurrentAge(final HttpCacheEntry e, final Date d) {
                 assertSame(entry, e);
                 assertEquals(now, d);
-                return 6;
+                return TimeValue.ofSeconds(6);
             }
             @Override
-            public long getFreshnessLifetimeSecs(final HttpCacheEntry e) {
+            public TimeValue getFreshnessLifetime(final HttpCacheEntry e) {
                 assertSame(entry, e);
-                return 10;
+                return TimeValue.ofSeconds(10);
             }
         };
         assertTrue(impl.isResponseFresh(entry, now));
@@ -268,15 +269,15 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
         impl = new CacheValidityPolicy() {
             @Override
-            public long getCurrentAgeSecs(final HttpCacheEntry e, final Date d) {
+            public TimeValue getCurrentAge(final HttpCacheEntry e, final Date d) {
                 assertEquals(now, d);
                 assertSame(entry, e);
-                return 6;
+                return TimeValue.ofSeconds(6);
             }
             @Override
-            public long getFreshnessLifetimeSecs(final HttpCacheEntry e) {
+            public TimeValue getFreshnessLifetime(final HttpCacheEntry e) {
                 assertSame(entry, e);
-                return 6;
+                return TimeValue.ofSeconds(6);
             }
         };
         assertFalse(impl.isResponseFresh(entry, now));
@@ -287,15 +288,15 @@ public class TestCacheValidityPolicy {
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
         impl = new CacheValidityPolicy() {
             @Override
-            public long getCurrentAgeSecs(final HttpCacheEntry e, final Date d) {
+            public TimeValue getCurrentAge(final HttpCacheEntry e, final Date d) {
                 assertEquals(now, d);
                 assertSame(entry, e);
-                return 10;
+                return TimeValue.ofSeconds(10);
             }
             @Override
-            public long getFreshnessLifetimeSecs(final HttpCacheEntry e) {
+            public TimeValue getFreshnessLifetime(final HttpCacheEntry e) {
                 assertSame(entry, e);
-                return 6;
+                return TimeValue.ofSeconds(6);
             }
         };
         assertFalse(impl.isResponseFresh(entry, now));
@@ -364,21 +365,24 @@ public class TestCacheValidityPolicy {
     public void testNegativeAgeHeaderValueReturnsMaxAge() {
         final Header[] headers = new Header[] { new BasicHeader("Age", "-100") };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(CacheValidityPolicy.MAX_AGE, impl.getAgeValue(entry));
+        // in seconds
+        assertEquals(CacheValidityPolicy.MAX_AGE.toSeconds(), impl.getAgeValue(entry));
     }
 
     @Test
     public void testMalformedAgeHeaderValueReturnsMaxAge() {
         final Header[] headers = new Header[] { new BasicHeader("Age", "asdf") };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(CacheValidityPolicy.MAX_AGE, impl.getAgeValue(entry));
+        // in seconds
+        assertEquals(CacheValidityPolicy.MAX_AGE.toSeconds(), impl.getAgeValue(entry));
     }
 
     @Test
     public void testMalformedCacheControlMaxAgeHeaderReturnsZero() {
         final Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=asdf") };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertEquals(0, impl.getMaxAge(entry));
+        // in seconds
+        assertEquals(0L, impl.getMaxAge(entry));
     }
 
     @Test
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachedHttpResponseGenerator.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachedHttpResponseGenerator.java
index 4e2d0eb..ace354b 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachedHttpResponseGenerator.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachedHttpResponseGenerator.java
@@ -40,6 +40,7 @@ import org.apache.hc.client5.http.cache.HttpCacheEntry;
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.util.TimeValue;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -108,11 +109,11 @@ public class TestCachedHttpResponseGenerator {
 
     @Test
     public void testAgeHeaderIsPopulatedWithCurrentAgeOfCacheEntryIfNonZero() throws Exception {
-        currentAge(10L);
+        currentAge(TimeValue.ofSeconds(10L));
 
         final SimpleHttpResponse response = impl.generateResponse(request, entry);
 
-        verify(mockValidityPolicy).getCurrentAgeSecs(same(entry), isA(Date.class));
+        verify(mockValidityPolicy).getCurrentAge(same(entry), isA(Date.class));
 
         final Header ageHdr = response.getFirstHeader("Age");
         Assert.assertNotNull(ageHdr);
@@ -121,11 +122,11 @@ public class TestCachedHttpResponseGenerator {
 
     @Test
     public void testAgeHeaderIsNotPopulatedIfCurrentAgeOfCacheEntryIsZero() throws Exception {
-        currentAge(0L);
+        currentAge(TimeValue.ofSeconds(0L));
 
         final SimpleHttpResponse response = impl.generateResponse(request, entry);
 
-        verify(mockValidityPolicy).getCurrentAgeSecs(same(entry), isA(Date.class));
+        verify(mockValidityPolicy).getCurrentAge(same(entry), isA(Date.class));
 
         final Header ageHdr = response.getFirstHeader("Age");
         Assert.assertNull(ageHdr);
@@ -133,21 +134,21 @@ public class TestCachedHttpResponseGenerator {
 
     @Test
     public void testAgeHeaderIsPopulatedWithMaxAgeIfCurrentAgeTooBig() throws Exception {
-        currentAge(CacheValidityPolicy.MAX_AGE + 1L);
+        currentAge(TimeValue.ofSeconds(CacheValidityPolicy.MAX_AGE.toSeconds() + 1L));
 
         final SimpleHttpResponse response = impl.generateResponse(request, entry);
 
-        verify(mockValidityPolicy).getCurrentAgeSecs(same(entry), isA(Date.class));
+        verify(mockValidityPolicy).getCurrentAge(same(entry), isA(Date.class));
 
         final Header ageHdr = response.getFirstHeader("Age");
         Assert.assertNotNull(ageHdr);
-        Assert.assertEquals(CacheValidityPolicy.MAX_AGE, Long.parseLong(ageHdr.getValue()));
+        Assert.assertEquals(CacheValidityPolicy.MAX_AGE.toSeconds(), Long.parseLong(ageHdr.getValue()));
     }
 
-    private void currentAge(final long sec) {
+    private void currentAge(final TimeValue age) {
         when(
-                mockValidityPolicy.getCurrentAgeSecs(same(entry),
-                        isA(Date.class))).thenReturn(sec);
+                mockValidityPolicy.getCurrentAge(same(entry),
+                        isA(Date.class))).thenReturn(age);
     }
 
     @Test
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java
index 853a595..eb56165 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java
@@ -79,6 +79,7 @@ import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
 import org.apache.hc.core5.http.message.BasicHeader;
 import org.apache.hc.core5.net.URIAuthority;
 import org.apache.hc.core5.util.ByteArrayBuffer;
+import org.apache.hc.core5.util.TimeValue;
 import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.easymock.IExpectationSetters;
@@ -316,7 +317,7 @@ public abstract class TestCachingExecChain {
         cacheEntrySuitable(true);
         responseIsGeneratedFromCache(SimpleHttpResponse.create(HttpStatus.SC_OK));
         requestIsFatallyNonCompliant(null);
-        entryHasStaleness(0L);
+        entryHasStaleness(TimeValue.ZERO_MILLISECONDS);
 
         replayMocks();
         final ClassicHttpResponse result = execute(request);
@@ -353,7 +354,7 @@ public abstract class TestCachingExecChain {
         cacheEntrySuitable(true);
         getCacheEntryReturns(mockCacheEntry);
         responseIsGeneratedFromCache(SimpleHttpResponse.create(HttpStatus.SC_OK));
-        entryHasStaleness(0L);
+        entryHasStaleness(TimeValue.ZERO_MILLISECONDS);
 
         replayMocks();
         execute(request);
@@ -1348,7 +1349,7 @@ public abstract class TestCachingExecChain {
         getCacheEntryReturns(entry);
         cacheEntrySuitable(true);
         responseIsGeneratedFromCache(SimpleHttpResponse.create(HttpStatus.SC_OK));
-        entryHasStaleness(0);
+        entryHasStaleness(TimeValue.ZERO_MILLISECONDS);
 
         replayMocks();
         final ClassicHttpResponse resp = execute(request);
@@ -1675,9 +1676,9 @@ public abstract class TestCachingExecChain {
             .andReturn(suitable);
     }
 
-    private void entryHasStaleness(final long staleness) {
+    private void entryHasStaleness(final TimeValue staleness) {
         expect(
-            mockValidityPolicy.getStalenessSecs((HttpCacheEntry) anyObject(), (Date) anyObject()))
+            mockValidityPolicy.getStaleness((HttpCacheEntry) anyObject(), (Date) anyObject()))
             .andReturn(staleness);
     }