You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2017/12/20 10:49:28 UTC
[3/3] httpcomponents-client git commit: New APIs for cache entry bulk
retrieval; bulk retrieval support by Memcached storage implementation
New APIs for cache entry bulk retrieval; bulk retrieval support by Memcached storage implementation
Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/29666a1a
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/29666a1a
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/29666a1a
Branch: refs/heads/master
Commit: 29666a1ad4a6c3b56cfec740ccc8093f0ad57812
Parents: 002f40f
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Fri Dec 15 14:06:23 2017 +0100
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Wed Dec 20 11:46:57 2017 +0100
----------------------------------------------------------------------
.../http/cache/HttpAsyncCacheStorage.java | 13 +++
.../cache/HttpAsyncCacheStorageAdaptor.java | 14 +++
.../hc/client5/http/cache/HttpCacheStorage.java | 15 +++
.../AbstractSerializingAsyncCacheStorage.java | 52 +++++++++
.../cache/AbstractSerializingCacheStorage.java | 29 ++++-
.../http/impl/cache/BasicHttpCacheStorage.java | 20 +++-
.../impl/cache/ManagedHttpCacheStorage.java | 16 +++
.../cache/ehcache/EhcacheHttpCacheStorage.java | 16 +++
.../MemcachedHttpAsyncCacheStorage.java | 31 ++++++
.../memcached/MemcachedHttpCacheStorage.java | 13 +++
.../http/impl/cache/SimpleHttpCacheStorage.java | 15 ++-
...estAbstractSerializingAsyncCacheStorage.java | 107 +++++++++++++++++++
.../TestAbstractSerializingCacheStorage.java | 86 ++++++++++++++-
13 files changed, 423 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorage.java
index 4ef0ce7..72064b3 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorage.java
@@ -26,6 +26,9 @@
*/
package org.apache.hc.client5.http.cache;
+import java.util.Collection;
+import java.util.Map;
+
import org.apache.hc.core5.concurrent.Cancellable;
import org.apache.hc.core5.concurrent.FutureCallback;
@@ -87,4 +90,14 @@ public interface HttpAsyncCacheStorage {
Cancellable updateEntry(
String key, HttpCacheCASOperation casOperation, FutureCallback<Boolean> callback);
+
+ /**
+ * Retrieves multiple cache entries stored under the given keys. Some implementations
+ * may use a single bulk operation to do the retrieval.
+ *
+ * @param keys cache keys
+ * @param callback result callback
+ */
+ Cancellable getEntries(Collection<String> keys, FutureCallback<Map<String, HttpCacheEntry>> callback);
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorageAdaptor.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorageAdaptor.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorageAdaptor.java
index c991fd7..d5199af 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorageAdaptor.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpAsyncCacheStorageAdaptor.java
@@ -26,6 +26,9 @@
*/
package org.apache.hc.client5.http.cache;
+import java.util.Collection;
+import java.util.Map;
+
import org.apache.hc.core5.concurrent.Cancellable;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.util.Args;
@@ -95,4 +98,15 @@ public final class HttpAsyncCacheStorageAdaptor implements HttpAsyncCacheStorage
return NOOP_CANCELLABLE;
}
+ public Cancellable getEntries(final Collection<String> keys, final FutureCallback<Map<String, HttpCacheEntry>> callback) {
+ Args.notNull(keys, "Key");
+ Args.notNull(callback, "Callback");
+ try {
+ callback.completed(cacheStorage.getEntries(keys));
+ } catch (final Exception ex) {
+ callback.failed(ex);
+ }
+ return NOOP_CANCELLABLE;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheStorage.java
index e58efcb..b4a459e 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheStorage.java
@@ -26,6 +26,9 @@
*/
package org.apache.hc.client5.http.cache;
+import java.util.Collection;
+import java.util.Map;
+
/**
* {@literal HttpCacheStorage} represents an abstract HTTP cache
* storage backend that can then be plugged into the classic
@@ -72,4 +75,16 @@ public interface HttpCacheStorage {
void updateEntry(
String key, HttpCacheCASOperation casOperation) throws ResourceIOException, HttpCacheUpdateException;
+
+ /**
+ * Retrieves multiple cache entries stored under the given keys. Some implementations
+ * may use a single bulk operation to do the retrieval.
+ *
+ * @param keys cache keys
+ * @return an map of {@link HttpCacheEntry}s.
+ *
+ * @since 5.0
+ */
+ Map<String, HttpCacheEntry> getEntries(Collection<String> keys) throws ResourceIOException;
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingAsyncCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingAsyncCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingAsyncCacheStorage.java
index 36c055f..69eb18c 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingAsyncCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingAsyncCacheStorage.java
@@ -26,6 +26,11 @@
*/
package org.apache.hc.client5.http.impl.cache;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.hc.client5.http.cache.HttpAsyncCacheStorage;
@@ -68,6 +73,8 @@ public abstract class AbstractSerializingAsyncCacheStorage<T, CAS> implements Ht
protected abstract Cancellable delete(String storageKey, FutureCallback<Boolean> callback);
+ protected abstract Cancellable bulkRestore(Collection<String> storageKeys, FutureCallback<Map<String, T>> callback);
+
@Override
public final Cancellable putEntry(
final String key, final HttpCacheEntry entry, final FutureCallback<Boolean> callback) {
@@ -225,4 +232,49 @@ public abstract class AbstractSerializingAsyncCacheStorage<T, CAS> implements Ht
}
}
+ @Override
+ public final Cancellable getEntries(final Collection<String> keys, final FutureCallback<Map<String, HttpCacheEntry>> callback) {
+ Args.notNull(keys, "Storage keys");
+ Args.notNull(callback, "Callback");
+ try {
+ final List<String> storageKeys = new ArrayList<>(keys.size());
+ for (final String key: keys) {
+ storageKeys.add(digestToStorageKey(key));
+ }
+ return bulkRestore(storageKeys, new FutureCallback<Map<String, T>>() {
+
+ @Override
+ public void completed(final Map<String, T> storageObjects) {
+ try {
+ final Map<String, HttpCacheEntry> resultMap = new HashMap<>();
+ for (final Map.Entry<String, T> storageEntry: storageObjects.entrySet()) {
+ final String key = storageEntry.getKey();
+ final HttpCacheStorageEntry entry = serializer.deserialize(storageEntry.getValue());
+ if (key.equals(entry.getKey())) {
+ resultMap.put(key, entry.getContent());
+ }
+ }
+ callback.completed(resultMap);
+ } catch (final Exception ex) {
+ callback.failed(ex);
+ }
+ }
+
+ @Override
+ public void failed(final Exception ex) {
+ callback.failed(ex);
+ }
+
+ @Override
+ public void cancelled() {
+ callback.cancelled();
+ }
+
+ });
+ } catch (final Exception ex) {
+ callback.failed(ex);
+ return NOOP_CANCELLABLE;
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingCacheStorage.java
index 6e59bb8..4a5ae98 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/AbstractSerializingCacheStorage.java
@@ -26,11 +26,17 @@
*/
package org.apache.hc.client5.http.impl.cache;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.hc.client5.http.cache.HttpCacheCASOperation;
import org.apache.hc.client5.http.cache.HttpCacheEntry;
import org.apache.hc.client5.http.cache.HttpCacheEntrySerializer;
import org.apache.hc.client5.http.cache.HttpCacheStorage;
import org.apache.hc.client5.http.cache.HttpCacheStorageEntry;
-import org.apache.hc.client5.http.cache.HttpCacheCASOperation;
import org.apache.hc.client5.http.cache.HttpCacheUpdateException;
import org.apache.hc.client5.http.cache.ResourceIOException;
import org.apache.hc.core5.util.Args;
@@ -64,6 +70,8 @@ public abstract class AbstractSerializingCacheStorage<T, CAS> implements HttpCac
protected abstract void delete(String storageKey) throws ResourceIOException;
+ protected abstract Map<String, T> bulkRestore(Collection<String> storageKeys) throws ResourceIOException;
+
@Override
public final void putEntry(final String key, final HttpCacheEntry entry) throws ResourceIOException {
final String storageKey = digestToStorageKey(key);
@@ -124,4 +132,23 @@ public abstract class AbstractSerializingCacheStorage<T, CAS> implements HttpCac
}
}
+ @Override
+ public final Map<String, HttpCacheEntry> getEntries(final Collection<String> keys) throws ResourceIOException {
+ Args.notNull(keys, "Storage keys");
+ final List<String> storageKeys = new ArrayList<>(keys.size());
+ for (final String key: keys) {
+ storageKeys.add(digestToStorageKey(key));
+ }
+ final Map<String, T> storageObjectMap = bulkRestore(storageKeys);
+ final Map<String, HttpCacheEntry> resultMap = new HashMap<>();
+ for (final Map.Entry<String, T> storageEntry: storageObjectMap.entrySet()) {
+ final String key = storageEntry.getKey();
+ final HttpCacheStorageEntry entry = serializer.deserialize(storageEntry.getValue());
+ if (key.equals(entry.getKey())) {
+ resultMap.put(key, entry.getContent());
+ }
+ }
+ return resultMap;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCacheStorage.java
index e908de2..e02be0f 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/BasicHttpCacheStorage.java
@@ -26,12 +26,17 @@
*/
package org.apache.hc.client5.http.impl.cache;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.hc.client5.http.cache.HttpCacheCASOperation;
import org.apache.hc.client5.http.cache.HttpCacheEntry;
import org.apache.hc.client5.http.cache.HttpCacheStorage;
-import org.apache.hc.client5.http.cache.HttpCacheCASOperation;
import org.apache.hc.client5.http.cache.ResourceIOException;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.util.Args;
/**
* Basic {@link HttpCacheStorage} implementation backed by an instance of
@@ -97,4 +102,17 @@ public class BasicHttpCacheStorage implements HttpCacheStorage {
entries.put(url, casOperation.execute(existingEntry));
}
+ @Override
+ public Map<String, HttpCacheEntry> getEntries(final Collection<String> keys) throws ResourceIOException {
+ Args.notNull(keys, "Key");
+ final Map<String, HttpCacheEntry> resultMap = new HashMap<>(keys.size());
+ for (final String key: keys) {
+ final HttpCacheEntry entry = getEntry(key);
+ if (entry != null) {
+ resultMap.put(key, entry);
+ }
+ }
+ return resultMap;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ManagedHttpCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ManagedHttpCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ManagedHttpCacheStorage.java
index 952e40c..a89c667 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ManagedHttpCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ManagedHttpCacheStorage.java
@@ -28,7 +28,10 @@ package org.apache.hc.client5.http.impl.cache;
import java.io.Closeable;
import java.lang.ref.ReferenceQueue;
+import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -150,6 +153,19 @@ public class ManagedHttpCacheStorage implements HttpCacheStorage, Closeable {
}
}
+ @Override
+ public Map<String, HttpCacheEntry> getEntries(final Collection<String> keys) throws ResourceIOException {
+ Args.notNull(keys, "Key");
+ final Map<String, HttpCacheEntry> resultMap = new HashMap<>(keys.size());
+ for (final String key: keys) {
+ final HttpCacheEntry entry = getEntry(key);
+ if (entry != null) {
+ resultMap.put(key, entry);
+ }
+ }
+ return resultMap;
+ }
+
public void cleanResources() {
if (this.active.get()) {
ResourceReference ref;
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ehcache/EhcacheHttpCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ehcache/EhcacheHttpCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ehcache/EhcacheHttpCacheStorage.java
index c3d7a38..1053bdb 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ehcache/EhcacheHttpCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ehcache/EhcacheHttpCacheStorage.java
@@ -26,6 +26,10 @@
*/
package org.apache.hc.client5.http.impl.cache.ehcache;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
import org.apache.hc.client5.http.cache.HttpCacheEntrySerializer;
import org.apache.hc.client5.http.cache.HttpCacheStorageEntry;
import org.apache.hc.client5.http.cache.ResourceIOException;
@@ -131,4 +135,16 @@ public class EhcacheHttpCacheStorage<T> extends AbstractSerializingCacheStorage<
cache.remove(storageKey);
}
+ @Override
+ protected Map<String, T> bulkRestore(final Collection<String> storageKeys) throws ResourceIOException {
+ final Map<String, T> resultMap = new HashMap<>();
+ for (final String storageKey: storageKeys) {
+ final T storageObject = cache.get(storageKey);
+ if (storageObject != null) {
+ resultMap.put(storageKey, storageObject);
+ }
+ }
+ return resultMap;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpAsyncCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpAsyncCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpAsyncCacheStorage.java
index 478c578..296b85a 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpAsyncCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpAsyncCacheStorage.java
@@ -28,6 +28,9 @@ package org.apache.hc.client5.http.impl.cache.memcached;
import java.io.IOException;
import java.net.InetSocketAddress;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.apache.hc.client5.http.cache.HttpCacheEntrySerializer;
@@ -42,6 +45,9 @@ import org.apache.hc.core5.util.Args;
import net.spy.memcached.CASResponse;
import net.spy.memcached.CASValue;
import net.spy.memcached.MemcachedClient;
+import net.spy.memcached.internal.BulkFuture;
+import net.spy.memcached.internal.BulkGetCompletionListener;
+import net.spy.memcached.internal.BulkGetFuture;
import net.spy.memcached.internal.GetCompletionListener;
import net.spy.memcached.internal.GetFuture;
import net.spy.memcached.internal.OperationCompletionListener;
@@ -247,4 +253,29 @@ public class MemcachedHttpAsyncCacheStorage extends AbstractBinaryAsyncCacheStor
return operation(client.delete(storageKey), callback);
}
+ @Override
+ protected Cancellable bulkRestore(final Collection<String> storageKeys, final FutureCallback<Map<String, byte[]>> callback) {
+ final BulkFuture<Map<String, Object>> future = client.asyncGetBulk(storageKeys);
+ future.addListener(new BulkGetCompletionListener() {
+
+ @Override
+ public void onComplete(final BulkGetFuture<?> future) throws Exception {
+ final Map<String, ?> storageObjectMap = future.get();
+ final Map<String, byte[]> resultMap = new HashMap<>(storageObjectMap.size());
+ for (final Map.Entry<String, ?> resultEntry: storageObjectMap.entrySet()) {
+ resultMap.put(resultEntry.getKey(), castAsByteArray(resultEntry.getValue()));
+ }
+ callback.completed(resultMap);
+ }
+ });
+ return new Cancellable() {
+
+ @Override
+ public boolean cancel() {
+ return future.cancel(true);
+ }
+
+ };
+ }
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpCacheStorage.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpCacheStorage.java
index 6a6195c..7df45b9 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpCacheStorage.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/MemcachedHttpCacheStorage.java
@@ -28,6 +28,9 @@ package org.apache.hc.client5.http.impl.cache.memcached;
import java.io.IOException;
import java.net.InetSocketAddress;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import org.apache.hc.client5.http.cache.HttpCacheEntrySerializer;
import org.apache.hc.client5.http.cache.ResourceIOException;
@@ -182,4 +185,14 @@ public class MemcachedHttpCacheStorage extends AbstractBinaryCacheStorage<CASVal
client.delete(storageKey);
}
+ @Override
+ protected Map<String, byte[]> bulkRestore(final Collection<String> storageKeys) throws ResourceIOException {
+ final Map<String, ?> storageObjectMap = client.getBulk(storageKeys);
+ final Map<String, byte[]> resultMap = new HashMap<>(storageObjectMap.size());
+ for (final Map.Entry<String, ?> resultEntry: storageObjectMap.entrySet()) {
+ resultMap.put(resultEntry.getKey(), castAsByteArray(resultEntry.getValue()));
+ }
+ return resultMap;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/SimpleHttpCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/SimpleHttpCacheStorage.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/SimpleHttpCacheStorage.java
index 0340e79..8dcfad7 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/SimpleHttpCacheStorage.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/SimpleHttpCacheStorage.java
@@ -26,12 +26,13 @@
*/
package org.apache.hc.client5.http.impl.cache;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import org.apache.hc.client5.http.cache.HttpCacheCASOperation;
import org.apache.hc.client5.http.cache.HttpCacheEntry;
import org.apache.hc.client5.http.cache.HttpCacheStorage;
-import org.apache.hc.client5.http.cache.HttpCacheCASOperation;
import org.apache.hc.client5.http.cache.ResourceIOException;
class SimpleHttpCacheStorage implements HttpCacheStorage {
@@ -65,4 +66,16 @@ class SimpleHttpCacheStorage implements HttpCacheStorage {
map.put(key,v2);
}
+ @Override
+ public Map<String, HttpCacheEntry> getEntries(final Collection<String> keys) throws ResourceIOException {
+ final Map<String, HttpCacheEntry> resultMap = new HashMap<>(keys.size());
+ for (final String key: keys) {
+ final HttpCacheEntry entry = getEntry(key);
+ if (entry != null) {
+ resultMap.put(key, entry);
+ }
+ }
+ return resultMap;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestAbstractSerializingAsyncCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestAbstractSerializingAsyncCacheStorage.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestAbstractSerializingAsyncCacheStorage.java
index 7070c89..8e5455e 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestAbstractSerializingAsyncCacheStorage.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestAbstractSerializingAsyncCacheStorage.java
@@ -26,6 +26,13 @@
*/
package org.apache.hc.client5.http.impl.cache;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.hc.client5.http.cache.HttpCacheCASOperation;
@@ -57,6 +64,8 @@ public class TestAbstractSerializingAsyncCacheStorage {
private FutureCallback<Boolean> operationCallback;
@Mock
private FutureCallback<HttpCacheEntry> cacheEntryCallback;
+ @Mock
+ private FutureCallback<Map<String, HttpCacheEntry>> bulkCacheEntryCallback;
private AbstractBinaryAsyncCacheStorage<String> impl;
@@ -447,4 +456,102 @@ public class TestAbstractSerializingAsyncCacheStorage {
Mockito.verify(operationCallback).failed(Mockito.<HttpCacheUpdateException>any());
}
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testBulkGet() throws Exception {
+ final String key1 = "foo this";
+ final String key2 = "foo that";
+ final String storageKey1 = "bar this";
+ final String storageKey2 = "bar that";
+ final HttpCacheEntry value1 = HttpTestUtils.makeCacheEntry();
+ final HttpCacheEntry value2 = HttpTestUtils.makeCacheEntry();
+
+ when(impl.digestToStorageKey(key1)).thenReturn(storageKey1);
+ when(impl.digestToStorageKey(key2)).thenReturn(storageKey2);
+
+ when(impl.bulkRestore(
+ Mockito.<String>anyCollection(),
+ Mockito.<FutureCallback<Map<String, byte[]>>>any())).thenAnswer(new Answer<Cancellable>() {
+
+ @Override
+ public Cancellable answer(final InvocationOnMock invocation) throws Throwable {
+ final Collection<String> keys = invocation.getArgument(0);
+ final FutureCallback<Map<String, byte[]>> callback = invocation.getArgument(1);
+ final Map<String, byte[]> resultMap = new HashMap<>();
+ if (keys.contains(storageKey1)) {
+ resultMap.put(storageKey1, serialize(key1, value1));
+ }
+ if (keys.contains(storageKey2)) {
+ resultMap.put(storageKey2, serialize(key2, value2));
+ }
+ callback.completed(resultMap);
+ return cancellable;
+ }
+ });
+
+ impl.getEntries(Arrays.asList(key1, key2), bulkCacheEntryCallback);
+ final ArgumentCaptor<Map<String, HttpCacheEntry>> argumentCaptor = ArgumentCaptor.forClass(Map.class);
+ Mockito.verify(bulkCacheEntryCallback).completed(argumentCaptor.capture());
+
+ final Map<String, HttpCacheEntry> entryMap = argumentCaptor.getValue();
+ Assert.assertThat(entryMap, CoreMatchers.notNullValue());
+ Assert.assertThat(entryMap.get(key1), HttpCacheEntryMatcher.equivalent(value1));
+ Assert.assertThat(entryMap.get(key2), HttpCacheEntryMatcher.equivalent(value2));
+
+ verify(impl).digestToStorageKey(key1);
+ verify(impl).digestToStorageKey(key2);
+ verify(impl).bulkRestore(
+ Mockito.eq(Arrays.asList(storageKey1, storageKey2)),
+ Mockito.<FutureCallback<Map<String, byte[]>>>any());
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testBulkGetKeyMismatch() throws Exception {
+ final String key1 = "foo this";
+ final String key2 = "foo that";
+ final String storageKey1 = "bar this";
+ final String storageKey2 = "bar that";
+ final HttpCacheEntry value1 = HttpTestUtils.makeCacheEntry();
+ final HttpCacheEntry value2 = HttpTestUtils.makeCacheEntry();
+
+ when(impl.digestToStorageKey(key1)).thenReturn(storageKey1);
+ when(impl.digestToStorageKey(key2)).thenReturn(storageKey2);
+
+ when(impl.bulkRestore(
+ Mockito.<String>anyCollection(),
+ Mockito.<FutureCallback<Map<String, byte[]>>>any())).thenAnswer(new Answer<Cancellable>() {
+
+ @Override
+ public Cancellable answer(final InvocationOnMock invocation) throws Throwable {
+ final Collection<String> keys = invocation.getArgument(0);
+ final FutureCallback<Map<String, byte[]>> callback = invocation.getArgument(1);
+ final Map<String, byte[]> resultMap = new HashMap<>();
+ if (keys.contains(storageKey1)) {
+ resultMap.put(storageKey1, serialize(key1, value1));
+ }
+ if (keys.contains(storageKey2)) {
+ resultMap.put(storageKey2, serialize("not foo", value2));
+ }
+ callback.completed(resultMap);
+ return cancellable;
+ }
+ });
+
+ impl.getEntries(Arrays.asList(key1, key2), bulkCacheEntryCallback);
+ final ArgumentCaptor<Map<String, HttpCacheEntry>> argumentCaptor = ArgumentCaptor.forClass(Map.class);
+ Mockito.verify(bulkCacheEntryCallback).completed(argumentCaptor.capture());
+
+ final Map<String, HttpCacheEntry> entryMap = argumentCaptor.getValue();
+ Assert.assertThat(entryMap, CoreMatchers.notNullValue());
+ Assert.assertThat(entryMap.get(key1), HttpCacheEntryMatcher.equivalent(value1));
+ Assert.assertThat(entryMap.get(key2), CoreMatchers.nullValue());
+
+ verify(impl).digestToStorageKey(key1);
+ verify(impl).digestToStorageKey(key2);
+ verify(impl).bulkRestore(
+ Mockito.eq(Arrays.asList(storageKey1, storageKey2)),
+ Mockito.<FutureCallback<Map<String, byte[]>>>any());
+ }
+
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/29666a1a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestAbstractSerializingCacheStorage.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestAbstractSerializingCacheStorage.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestAbstractSerializingCacheStorage.java
index 2becb4a..0537be7 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestAbstractSerializingCacheStorage.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestAbstractSerializingCacheStorage.java
@@ -30,9 +30,14 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.hc.client5.http.cache.HttpCacheCASOperation;
import org.apache.hc.client5.http.cache.HttpCacheEntry;
import org.apache.hc.client5.http.cache.HttpCacheStorageEntry;
-import org.apache.hc.client5.http.cache.HttpCacheCASOperation;
import org.apache.hc.client5.http.cache.HttpCacheUpdateException;
import org.apache.hc.client5.http.cache.ResourceIOException;
import org.hamcrest.CoreMatchers;
@@ -42,6 +47,8 @@ import org.junit.Test;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
@SuppressWarnings("boxing") // test code
public class TestAbstractSerializingCacheStorage {
@@ -253,4 +260,81 @@ public class TestAbstractSerializingCacheStorage {
verify(impl, Mockito.times(3)).getStorageObject("stuff");
verify(impl, Mockito.times(3)).updateCAS(Mockito.eq("bar"), Mockito.eq("stuff"), Mockito.<byte[]>any());
}
+
+ @Test
+ public void testBulkGet() throws Exception {
+ final String key1 = "foo this";
+ final String key2 = "foo that";
+ final String storageKey1 = "bar this";
+ final String storageKey2 = "bar that";
+ final HttpCacheEntry value1 = HttpTestUtils.makeCacheEntry();
+ final HttpCacheEntry value2 = HttpTestUtils.makeCacheEntry();
+
+ when(impl.digestToStorageKey(key1)).thenReturn(storageKey1);
+ when(impl.digestToStorageKey(key2)).thenReturn(storageKey2);
+
+ when(impl.bulkRestore(Mockito.<String>anyCollection())).thenAnswer(new Answer<Map<String, byte[]>>() {
+
+ @Override
+ public Map<String, byte[]> answer(final InvocationOnMock invocation) throws Throwable {
+ final Collection<String> keys = invocation.getArgument(0);
+ final Map<String, byte[]> resultMap = new HashMap<>();
+ if (keys.contains(storageKey1)) {
+ resultMap.put(storageKey1, serialize(key1, value1));
+ }
+ if (keys.contains(storageKey2)) {
+ resultMap.put(storageKey2, serialize(key2, value2));
+ }
+ return resultMap;
+ }
+ });
+
+ final Map<String, HttpCacheEntry> entryMap = impl.getEntries(Arrays.asList(key1, key2));
+ Assert.assertThat(entryMap, CoreMatchers.notNullValue());
+ Assert.assertThat(entryMap.get(key1), HttpCacheEntryMatcher.equivalent(value1));
+ Assert.assertThat(entryMap.get(key2), HttpCacheEntryMatcher.equivalent(value2));
+
+ verify(impl).digestToStorageKey(key1);
+ verify(impl).digestToStorageKey(key2);
+ verify(impl).bulkRestore(Arrays.asList(storageKey1, storageKey2));
+ }
+
+ @Test
+ public void testBulkGetKeyMismatch() throws Exception {
+ final String key1 = "foo this";
+ final String key2 = "foo that";
+ final String storageKey1 = "bar this";
+ final String storageKey2 = "bar that";
+ final HttpCacheEntry value1 = HttpTestUtils.makeCacheEntry();
+ final HttpCacheEntry value2 = HttpTestUtils.makeCacheEntry();
+
+ when(impl.digestToStorageKey(key1)).thenReturn(storageKey1);
+ when(impl.digestToStorageKey(key2)).thenReturn(storageKey2);
+
+ when(impl.bulkRestore(Mockito.<String>anyCollection())).thenAnswer(new Answer<Map<String, byte[]>>() {
+
+ @Override
+ public Map<String, byte[]> answer(final InvocationOnMock invocation) throws Throwable {
+ final Collection<String> keys = invocation.getArgument(0);
+ final Map<String, byte[]> resultMap = new HashMap<>();
+ if (keys.contains(storageKey1)) {
+ resultMap.put(storageKey1, serialize(key1, value1));
+ }
+ if (keys.contains(storageKey2)) {
+ resultMap.put(storageKey2, serialize("not foo", value2));
+ }
+ return resultMap;
+ }
+ });
+
+ final Map<String, HttpCacheEntry> entryMap = impl.getEntries(Arrays.asList(key1, key2));
+ Assert.assertThat(entryMap, CoreMatchers.notNullValue());
+ Assert.assertThat(entryMap.get(key1), HttpCacheEntryMatcher.equivalent(value1));
+ Assert.assertThat(entryMap.get(key2), CoreMatchers.nullValue());
+
+ verify(impl).digestToStorageKey(key1);
+ verify(impl).digestToStorageKey(key2);
+ verify(impl).bulkRestore(Arrays.asList(storageKey1, storageKey2));
+ }
+
}