/** * Creates a functions which returns a value from a cache, if it exists. * Otherwise it calls the Supplier. * * @param cache the Cache * @param supplier the original Supplier * @param <K> the type of key * @param <R> the type of value * @return a supplier which is secured by a CircuitBreaker. */ static <K, R> CheckedFunction1<K, R> decorateCheckedSupplier(Cache<K, R> cache, CheckedFunction0<R> supplier){ return (K cacheKey) -> cache.computeIfAbsent(cacheKey, supplier); }
public <K> DecorateCheckedFunction<K, T> withCache(Cache<K, T> cache) { return Decorators.ofCheckedFunction(Cache.decorateCheckedSupplier(cache, supplier)); }
public <K> DecorateFunction<K, T> withCache(Cache<K, T> cache) { return Decorators.ofFunction(Cache.decorateSupplier(cache, supplier)); }
@Test public void shouldReturnCachedValue() throws Throwable { // Return the value from cache given(cache.get("testKey")).willReturn("Hello from cache"); Cache<String, String> cacheContext = Cache.of(cache); TestSubscriber<CacheEvent.Type> testSubscriber = toFlowable(cacheContext.getEventPublisher()) .map(CacheEvent::getEventType) .test(); CheckedFunction1<String, String> cachedFunction = Cache.decorateCheckedSupplier(cacheContext, () -> "Hello world"); String value = cachedFunction.apply("testKey"); assertThat(value).isEqualTo("Hello from cache"); assertThat(cacheContext.getMetrics().getNumberOfCacheHits()).isEqualTo(1); assertThat(cacheContext.getMetrics().getNumberOfCacheMisses()).isEqualTo(0); testSubscriber .assertValueCount(1) .assertValues(CacheEvent.Type.CACHE_HIT); }
@Test public void shouldConsumeOnCacheMissEvent() throws Throwable { // Given the cache does not contain the key given(cache.get("testKey")).willReturn(null); Cache<String, String> cacheContext = Cache.of(cache); cacheContext.getEventPublisher().onCacheMiss(event -> logger.info(event.getEventType().toString())); CheckedFunction1<String, String> cachedFunction = Cache.decorateCheckedSupplier(cacheContext, () -> "Hello world"); String value = cachedFunction.apply("testKey"); assertThat(value).isEqualTo("Hello world"); then(logger).should(times(1)).info("CACHE_MISS"); }
@Test public void shouldConsumeOnCacheHitEvent() throws Throwable { // Given the cache does not contain the key given(cache.get("testKey")).willReturn("Hello world"); Cache<String, String> cacheContext = Cache.of(cache); cacheContext.getEventPublisher().onCacheHit(event -> logger.info(event.getEventType().toString())); CheckedFunction1<String, String> cachedFunction = Cache.decorateCheckedSupplier(cacheContext, () -> "Hello world"); String value = cachedFunction.apply("testKey"); assertThat(value).isEqualTo("Hello world"); then(logger).should(times(1)).info("CACHE_HIT"); }
@Test public void shouldConsumeOnErrorEvent() throws Throwable { // Given the cache does not contain the key given(cache.get("testKey")).willThrow(new WebServiceException("BLA")); Cache<String, String> cacheContext = Cache.of(cache); cacheContext.getEventPublisher().onError(event -> logger.info(event.getEventType().toString())); CheckedFunction1<String, String> cachedFunction = Cache.decorateCheckedSupplier(cacheContext, () -> "Hello world"); String value = cachedFunction.apply("testKey"); assertThat(value).isEqualTo("Hello world"); then(logger).should(times(1)).info("ERROR"); }
@Test public void shouldReturnValueFromDecoratedSupplier() throws Throwable { // Given the cache does not contain the key given(cache.get("testKey")).willReturn(null); Cache<String, String> cacheContext = Cache.of(cache); TestSubscriber<CacheEvent.Type> testSubscriber = toFlowable(cacheContext.getEventPublisher()) .map(CacheEvent::getEventType) .test(); Function<String, String> cachedFunction = Cache.decorateSupplier(cacheContext, () -> "Hello world"); String value = cachedFunction.apply("testKey"); assertThat(value).isEqualTo("Hello world"); assertThat(cacheContext.getMetrics().getNumberOfCacheHits()).isEqualTo(0); assertThat(cacheContext.getMetrics().getNumberOfCacheMisses()).isEqualTo(1); then(cache).should().put("testKey", "Hello world"); testSubscriber .assertValueCount(1) .assertValues(CacheEvent.Type.CACHE_MISS); }
@Test public void shouldReturnValueFromDecoratedCallable() throws Throwable { // Given the cache does not contain the key given(cache.get("testKey")).willReturn(null); Cache<String, String> cacheContext = Cache.of(cache); TestSubscriber<CacheEvent.Type> testSubscriber = toFlowable(cacheContext.getEventPublisher()) .map(CacheEvent::getEventType) .test(); CheckedFunction1<String, String> cachedFunction = Cache.decorateCallable(cacheContext, () -> "Hello world"); String value = cachedFunction.apply("testKey"); assertThat(value).isEqualTo("Hello world"); assertThat(cacheContext.getMetrics().getNumberOfCacheHits()).isEqualTo(0); assertThat(cacheContext.getMetrics().getNumberOfCacheMisses()).isEqualTo(1); then(cache).should().put("testKey", "Hello world"); testSubscriber .assertValueCount(1) .assertValues(CacheEvent.Type.CACHE_MISS); }
@Test public void shouldReturnTheSameConsumer() { Cache<String, String> cacheContext = Cache.of(cache); Cache.EventPublisher eventPublisher = cacheContext.getEventPublisher(); Cache.EventPublisher eventPublisher2 = cacheContext.getEventPublisher(); assertThat(eventPublisher).isEqualTo(eventPublisher2); }
@SuppressWarnings("unchecked") @Test public void testDecorateSupplierWithCache() { javax.cache.Cache<String, String> cache = mock(javax.cache.Cache.class); // Given the cache contains the key given(cache.containsKey("testKey")).willReturn(true); // Return the value from cache given(cache.get("testKey")).willReturn("Hello from cache"); Function<String, String> cachedFunction = Decorators.ofSupplier(() -> "Hello world") .withCache(Cache.of(cache)) .decorate(); String value = cachedFunction.apply("testKey"); assertThat(value).isEqualTo("Hello from cache"); }
@Test public void shouldReturnValueFromDecoratedCallableBecauseOfException() throws Throwable { // Given the cache contains the key given(cache.get("testKey")).willThrow(new RuntimeException("Cache is not available")); Cache<String, String> cacheContext = Cache.of(cache); TestSubscriber<CacheEvent.Type> testSubscriber = toFlowable(cacheContext.getEventPublisher()) .map(CacheEvent::getEventType) .test(); CheckedFunction1<String, String> cachedFunction = Cache.decorateCheckedSupplier(cacheContext, () -> "Hello world"); String value = cachedFunction.apply("testKey"); assertThat(value).isEqualTo("Hello world"); assertThat(cacheContext.getMetrics().getNumberOfCacheHits()).isEqualTo(0); assertThat(cacheContext.getMetrics().getNumberOfCacheMisses()).isEqualTo(0); testSubscriber .assertValueCount(1) .assertValues(CacheEvent.Type.ERROR); } }
/** * Creates a functions which returns a value from a cache, if it exists. * Otherwise it calls the Supplier. * * @param cache the Cache * @param supplier the original Supplier * @param <K> the type of key * @param <R> the type of value * @return a supplier which is secured by a CircuitBreaker. */ static <K, R> Function<K, R> decorateSupplier(Cache<K, R> cache, Supplier<R> supplier){ return (K cacheKey) -> cache.computeIfAbsent(cacheKey, supplier::get); }
@SuppressWarnings("unchecked") @Test public void testDecorateCheckedSupplierWithCache() { javax.cache.Cache<String, String> cache = mock(javax.cache.Cache.class); // Given the cache contains the key given(cache.containsKey("testKey")).willReturn(true); // Return the value from cache given(cache.get("testKey")).willReturn("Hello from cache"); CheckedFunction1<String, String> cachedFunction = Decorators.ofCheckedSupplier(() -> "Hello world") .withCache(Cache.of(cache)) .decorate(); String value = Try.of(() -> cachedFunction.apply("testKey")).get(); assertThat(value).isEqualTo("Hello from cache"); }
@Test public void shouldReturnValueFromDecoratedCheckedSupplier() throws Throwable { // Given the cache does not contain the key given(cache.get("testKey")).willReturn(null); Cache<String, String> cacheContext = Cache.of(cache); TestSubscriber<CacheEvent.Type> testSubscriber = toFlowable(cacheContext.getEventPublisher()) .map(CacheEvent::getEventType) .test(); CheckedFunction1<String, String> cachedFunction = Cache.decorateCheckedSupplier(cacheContext, () -> "Hello world"); String value = cachedFunction.apply("testKey"); assertThat(value).isEqualTo("Hello world"); assertThat(cacheContext.getMetrics().getNumberOfCacheHits()).isEqualTo(0); assertThat(cacheContext.getMetrics().getNumberOfCacheMisses()).isEqualTo(1); then(cache).should().put("testKey", "Hello world"); testSubscriber .assertValueCount(1) .assertValues(CacheEvent.Type.CACHE_MISS); }
/** * Creates a functions which returns a value from a cache, if it exists. * Otherwise it calls the Callable. * * @param cache the Cache * @param callable the original Callable * @param <K> the type of key * @param <R> the type of value * @return a supplier which is secured by a CircuitBreaker. */ static <K, R> CheckedFunction1<K, R> decorateCallable(Cache<K, R> cache, Callable<R> callable){ return (K cacheKey) -> cache.computeIfAbsent(cacheKey, callable::call); }
@Test public void shouldReturnValueOfSupplier() throws Throwable { // Given the cache does not contain the key given(cache.get("testKey")).willReturn(null); willThrow(new RuntimeException("Cache is not available")).given(cache).put("testKey", "Hello world"); Cache<String, String> cacheContext = Cache.of(cache); TestSubscriber<CacheEvent.Type> testSubscriber = toFlowable(cacheContext.getEventPublisher()) .map(CacheEvent::getEventType) .test(); CheckedFunction1<String, String> cachedFunction = Cache.decorateCheckedSupplier(cacheContext, () -> "Hello world"); String value = cachedFunction.apply("testKey"); assertThat(value).isEqualTo("Hello world"); assertThat(cacheContext.getMetrics().getNumberOfCacheHits()).isEqualTo(0); assertThat(cacheContext.getMetrics().getNumberOfCacheMisses()).isEqualTo(1); testSubscriber .assertValueCount(2) .assertValues(CacheEvent.Type.CACHE_MISS, CacheEvent.Type.ERROR); }
/** * Creates a functions which returns a value from a cache, if it exists. * Otherwise it calls the Supplier. * * @param cache the Cache * @param supplier the original Supplier * @param <K> the type of key * @param <R> the type of value * @return a supplier which is secured by a CircuitBreaker. */ static <K, R> Function<K, R> decorateSupplier(Cache<K, R> cache, Supplier<R> supplier){ return (K cacheKey) -> cache.computeIfAbsent(cacheKey, supplier::get); }
/** * Creates a functions which returns a value from a cache, if it exists. * Otherwise it calls the Callable. * * @param cache the Cache * @param callable the original Callable * @param <K> the type of key * @param <R> the type of value * @return a supplier which is secured by a CircuitBreaker. */ static <K, R> CheckedFunction1<K, R> decorateCallable(Cache<K, R> cache, Callable<R> callable){ return (K cacheKey) -> cache.computeIfAbsent(cacheKey, callable::call); }
/** * Creates a functions which returns a value from a cache, if it exists. * Otherwise it calls the Supplier. * * @param cache the Cache * @param supplier the original Supplier * @param <K> the type of key * @param <R> the type of value * @return a supplier which is secured by a CircuitBreaker. */ static <K, R> CheckedFunction1<K, R> decorateCheckedSupplier(Cache<K, R> cache, CheckedFunction0<R> supplier){ return (K cacheKey) -> cache.computeIfAbsent(cacheKey, supplier); }