diff --git a/src/main/java/com/wego/httpcache/services/AsyncHttpCacheService.java b/src/main/java/com/wego/httpcache/services/AsyncHttpCacheService.java index 4eeae2f..9ea6d0d 100644 --- a/src/main/java/com/wego/httpcache/services/AsyncHttpCacheService.java +++ b/src/main/java/com/wego/httpcache/services/AsyncHttpCacheService.java @@ -12,4 +12,8 @@ Optional> executeRequest( Optional> executeRequest( Request request, AsyncCompletionHandlerBase handler, long ttl) throws Exception; + + Optional> executeRequest( + Request request, AsyncCompletionHandlerBase handler, long ttl, String cacheKey) + throws Exception; } diff --git a/src/main/java/com/wego/httpcache/services/impl/AsyncHttpCacheServiceImpl.java b/src/main/java/com/wego/httpcache/services/impl/AsyncHttpCacheServiceImpl.java index ca640e0..cb42fe7 100644 --- a/src/main/java/com/wego/httpcache/services/impl/AsyncHttpCacheServiceImpl.java +++ b/src/main/java/com/wego/httpcache/services/impl/AsyncHttpCacheServiceImpl.java @@ -13,10 +13,12 @@ import com.wego.httpcache.services.CachedResponseService; import java.util.Optional; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import redis.clients.util.MurmurHash; public class AsyncHttpCacheServiceImpl implements AsyncHttpCacheService { - + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncHttpCacheServiceImpl.class); private static final String DELIMITER = ":"; @Inject private CachedResponseService cachedResponseService; private String serviceName; @@ -34,24 +36,37 @@ public AsyncHttpCacheServiceImpl( @Override public Optional> executeRequest( Request request, AsyncCompletionHandlerBase handler) throws Exception { - return executeRequest(request, handler, ttl); + return executeRequest(request, handler, this.ttl); } @Override public Optional> executeRequest( Request request, AsyncCompletionHandlerBase handler, long ttl) throws Exception { + return executeRequest(request, handler, ttl, null); + } + + @Override + public Optional> executeRequest( + Request request, AsyncCompletionHandlerBase handler, long ttl, String cacheKey) + throws Exception { ListenableFuture responseListenableFuture = null; - String responseId = buildResponseId(request); - Optional cachedResponse = cachedResponseService.findById(responseId); + if (cacheKey == null) { + cacheKey = buildResponseId(request); + } + + Optional cachedResponse = cachedResponseService.findById(cacheKey); + + LOGGER.info("HTTP cache Provider: {} has ResponseID: {}", serviceName, cacheKey); if (cachedResponse.isPresent()) { + LOGGER.info("Found HTTP cache for Provider: {} with ResponseID: {}", serviceName, cacheKey); handler.onCompleted(cachedResponse.get()); } else { responseListenableFuture = this.asyncHttpClient.executeRequest( - request, buildCachingHandler(handler, responseId, ttl)); + request, buildCachingHandler(handler, cacheKey, ttl)); } return Optional.ofNullable(responseListenableFuture); @@ -61,6 +76,7 @@ private String buildResponseId(Request request) { String requestStringId = StringUtils.join( request, request.getStringData(), Lists.newArrayList(request.getCookies()).toString()); + return StringUtils.joinWith( DELIMITER, serviceName, String.valueOf(MurmurHash.hash64A(requestStringId.getBytes(), 0))); } @@ -73,6 +89,7 @@ private AsyncCompletionHandlerBase buildCachingHandler( public Response onCompleted(Response response) throws Exception { CachedResponse cachedResponse = new CachedResponse.Builder(response).setId(responseId).build(); + LOGGER.info("Save HTTP cache for provider {} with ResponseID {}", serviceName, responseId); cachedResponseService.save(cachedResponse, cachingTtl); return handler.onCompleted(response); diff --git a/src/test/java/com/wego/httpcache/services/impl/TestAsyncHttpCacheServiceImpl.java b/src/test/java/com/wego/httpcache/services/impl/TestAsyncHttpCacheServiceImpl.java index 761b819..7261d02 100644 --- a/src/test/java/com/wego/httpcache/services/impl/TestAsyncHttpCacheServiceImpl.java +++ b/src/test/java/com/wego/httpcache/services/impl/TestAsyncHttpCacheServiceImpl.java @@ -47,20 +47,16 @@ public class TestAsyncHttpCacheServiceImpl { private static final String SERVICE_NAME = "Service Name"; private static long CACHING_TTL = 60; - @Rule - public WireMockRule wireMockRule = new WireMockRule(8089); + @Rule public WireMockRule wireMockRule = new WireMockRule(8089); - @Spy - private AsyncHttpClient asyncHttpClient = new AsyncHttpClient(); + @Spy private AsyncHttpClient asyncHttpClient = new AsyncHttpClient(); @InjectMocks private AsyncHttpCacheService asyncHttpCacheService = new AsyncHttpCacheServiceImpl(SERVICE_NAME, asyncHttpClient, CACHING_TTL); - @Mock - private CachedResponseService cachedResponseService; - @Mock - private Request request; + @Mock private CachedResponseService cachedResponseService; + @Mock private Request request; @Test public void executeRequest_whenWasCached_getResponseFromCacheAndCallOnComplete() @@ -154,6 +150,44 @@ public void executeRequest_withTtl_whenWasNotCached_executeHttpRequestAndCacheNe assertThat(savedCachedResponses.get(0).getId()).isNotEmpty(); } + @Test + public void + executeRequest_withTtlAndCacheKey_whenWasNotCached_executeHttpRequestAndCacheNewResponse() + throws Exception { + final Request request = + new RequestBuilder().setMethod("GET").setUrl("http://localhost:8089/resources/").build(); + final List savedCachedResponses = Lists.newArrayList(); + final long customTtl = 10; + + stubFor( + get(urlEqualTo("/resources/")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "text/json") + .withBody("This is body"))); + + when(cachedResponseService.findById(anyString())).thenReturn(Optional.empty()); + when(cachedResponseService.save(any(), eq(customTtl))) + .thenAnswer( + invocation -> { + CachedResponse cr = invocation.getArgumentAt(0, CachedResponse.class); + savedCachedResponses.add(cr); + return Optional.of(cr); + }); + + Optional> responseListenableFuture = + asyncHttpCacheService.executeRequest( + request, new AsyncCompletionHandlerBase(), customTtl, "test"); + + responseListenableFuture.get().get(); + + verify(asyncHttpClient).executeRequest(any(), any()); + assertThat(savedCachedResponses.size()).isEqualTo(1); + assertThat(savedCachedResponses.get(0).getId()).isEqualTo("test"); + assertThat(savedCachedResponses.get(0).getId()).isNotEmpty(); + } + @Test public void buildResponseId_returnsDifferentIdsForDifferentRequest() throws Exception { @@ -198,12 +232,10 @@ public void buildResponseId_returnsDifferentIdsForDifferentRequest() throws Exce "POST", "http://localhost:8089/resources/", "param", "test2"); Request requestWithBody = - RequestFixture.createWithBody( - "POST", "http://localhost:8089/resources/", "test1"); + RequestFixture.createWithBody("POST", "http://localhost:8089/resources/", "test1"); Request requestWithDifferentBody = - RequestFixture.createWithBody( - "POST", "http://localhost:8089/resources/", "test2"); + RequestFixture.createWithBody("POST", "http://localhost:8089/resources/", "test2"); Method method = AsyncHttpCacheServiceImpl.class.getDeclaredMethod("buildResponseId", Request.class); @@ -211,19 +243,19 @@ public void buildResponseId_returnsDifferentIdsForDifferentRequest() throws Exce final List responseIds = Stream.of( - request, - requestWithDifferentUrl, - requestWithDifferentMethod, - requestWithParams, - requestWithDifferentParams, - requestWithCookie, - requestWithDifferentCookie, - requestWithHeader, - requestWithDifferentHeader, - requestWithQueryParams, - requestWithDifferentQueryParams, - requestWithBody, - requestWithDifferentBody) + request, + requestWithDifferentUrl, + requestWithDifferentMethod, + requestWithParams, + requestWithDifferentParams, + requestWithCookie, + requestWithDifferentCookie, + requestWithHeader, + requestWithDifferentHeader, + requestWithQueryParams, + requestWithDifferentQueryParams, + requestWithBody, + requestWithDifferentBody) .map( rq -> { try {