From fc52976c3d75f9199394bad8615ffbcb31bc93d2 Mon Sep 17 00:00:00 2001 From: stair <123031771+stair-aws@users.noreply.github.com> Date: Tue, 18 Apr 2023 14:58:46 -0400 Subject: [PATCH] Added `SupplierCache` (so it may be leveraged by StreamARN work). (#1096) --- .../amazon/kinesis/common/SupplierCache.java | 36 ++++++++++++ .../kinesis/common/SupplierCacheTest.java | 56 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 amazon-kinesis-client/src/main/java/software/amazon/kinesis/common/SupplierCache.java create mode 100644 amazon-kinesis-client/src/test/java/software/amazon/kinesis/common/SupplierCacheTest.java diff --git a/amazon-kinesis-client/src/main/java/software/amazon/kinesis/common/SupplierCache.java b/amazon-kinesis-client/src/main/java/software/amazon/kinesis/common/SupplierCache.java new file mode 100644 index 00000000..632e4b8f --- /dev/null +++ b/amazon-kinesis-client/src/main/java/software/amazon/kinesis/common/SupplierCache.java @@ -0,0 +1,36 @@ +package software.amazon.kinesis.common; + +import java.util.function.Supplier; + +import lombok.RequiredArgsConstructor; + +/** + * Caches results from a {@link Supplier}. Caching is especially useful when + * {@link Supplier#get()} is an expensive call that produces static results. + */ +@RequiredArgsConstructor +public class SupplierCache { + + private final Supplier supplier; + + private volatile T result; + + /** + * Returns the cached result. If the cache is null, the supplier will be + * invoked to populate the cache. + * + * @return cached result which may be null + */ + public T get() { + if (result == null) { + synchronized (this) { + // double-check lock + if (result == null) { + result = supplier.get(); + } + } + } + return result; + } + +} diff --git a/amazon-kinesis-client/src/test/java/software/amazon/kinesis/common/SupplierCacheTest.java b/amazon-kinesis-client/src/test/java/software/amazon/kinesis/common/SupplierCacheTest.java new file mode 100644 index 00000000..4df4f81d --- /dev/null +++ b/amazon-kinesis-client/src/test/java/software/amazon/kinesis/common/SupplierCacheTest.java @@ -0,0 +1,56 @@ +package software.amazon.kinesis.common; + +import java.util.function.Supplier; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SupplierCacheTest { + + private static final Object DUMMY_RESULT = SupplierCacheTest.class; + + @Mock + private Supplier mockSupplier; + + private SupplierCache cache; + + @Before + public void setUp() { + cache = new SupplierCache<>(mockSupplier); + } + + @Test + public void testCache() { + when(mockSupplier.get()).thenReturn(DUMMY_RESULT); + + final Object result1 = cache.get(); + final Object result2 = cache.get(); + + assertEquals(DUMMY_RESULT, result1); + assertSame(result1, result2); + verify(mockSupplier).get(); + } + + @Test + public void testCacheWithNullResult() { + when(mockSupplier.get()).thenReturn(null).thenReturn(DUMMY_RESULT); + + final Object result1 = cache.get(); + final Object result2 = cache.get(); + + assertNull(result1); + assertEquals(DUMMY_RESULT, result2); + verify(mockSupplier, times(2)).get(); + } +} \ No newline at end of file