Skip to content

Commit

Permalink
(jcabi#179) Expose cache via contructor
Browse files Browse the repository at this point in the history
  • Loading branch information
andreoss committed Sep 2, 2020
1 parent 02ea05e commit cb1fef9
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 29 deletions.
96 changes: 68 additions & 28 deletions src/main/java/com/jcabi/http/wire/CachingWire.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import java.net.URI;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import lombok.EqualsAndHashCode;
import lombok.ToString;
Expand Down Expand Up @@ -77,36 +78,43 @@
@Immutable
@ToString
@EqualsAndHashCode(of = {"origin", "regex"})
@SuppressWarnings("PMD.OnlyOneConstructorShouldDoInitialization")
public final class CachingWire implements Wire {

/**
* Loader.
*/
private static final CacheLoader<Wire,
LoadingCache<CachingWire.Query, Response>> LOADER =
new CacheLoader<Wire, LoadingCache<CachingWire.Query, Response>>() {
LoadingCache<Callable<Response>, Response>> LOADER =
new CacheLoader<Wire, LoadingCache<Callable<Response>, Response>>() {
@Override
public LoadingCache<CachingWire.Query, Response> load(
final Wire key) {
public LoadingCache<Callable<Response>, Response> load(
final Wire key
) {
return CacheBuilder.newBuilder().build(
new CacheLoader<CachingWire.Query, Response>() {
new CacheLoader<Callable<Response>, Response>() {
@Override
public Response load(final CachingWire.Query query)
throws IOException {
return query.fetch();
public Response load(final Callable<Response> query)
throws Exception {
return query.call();
}
}
);
}
};

/**
* Cache.
* Default cache.
*/
private static final LoadingCache<Wire,
LoadingCache<CachingWire.Query, Response>> CACHE =
LoadingCache<Callable<Response>, Response>> CACHE =
CacheBuilder.newBuilder().build(CachingWire.LOADER);

/**
* Default flushing regex.
*/
private static final String NEVER = "$never";

/**
* Original wire.
*/
Expand All @@ -117,12 +125,17 @@ public Response load(final CachingWire.Query query)
*/
private final transient String regex;

/**
* Cache.
*/
private final LoadingCache<Callable<Response>, Response> cache;

/**
* Public ctor.
* @param wire Original wire
*/
public CachingWire(final Wire wire) {
this(wire, "$never");
this(wire, CachingWire.NEVER);
}

/**
Expand All @@ -134,33 +147,62 @@ public CachingWire(final Wire wire) {
public CachingWire(final Wire wire, final String flsh) {
this.origin = wire;
this.regex = flsh;
this.cache = CACHE.getUnchecked(this);
}

/**
* Public ctor.
* @param wire Original wire
* @param storage Cache
* @since 1.17.4
*/
public CachingWire(
final Wire wire,
final LoadingCache<Callable<Response>, Response> storage
) {
this(wire, CachingWire.NEVER, storage);
}

/**
* Public ctor.
* @param wire Original wire
* @param flsh Flushing regular expression
* @param storage Cache
* @since 1.17.4
*/
public CachingWire(
final Wire wire,
final String flsh,
final LoadingCache<Callable<Response>, Response> storage
) {
this.origin = wire;
this.regex = flsh;
this.cache = storage;
}

// @checkstyle ParameterNumber (5 lines)
@Override
public Response send(final Request req, final String home,
public Response send(
final Request req, final String home,
final String method,
final Collection<Map.Entry<String, String>> headers,
final InputStream content,
final int connect,
final int read) throws IOException {
final int read
) throws IOException {
final URI uri = req.uri().get();
final StringBuilder label = new StringBuilder(Tv.HUNDRED)
.append(method).append(' ').append(uri.getPath());
if (uri.getQuery() != null) {
label.append('?').append(uri.getQuery());
}
if (label.toString().matches(this.regex)) {
try {
CachingWire.CACHE.get(this).invalidateAll();
} catch (final ExecutionException ex) {
throw new IllegalStateException(ex);
}
this.cache.invalidateAll();
}
final Response rsp;
if (method.equals(Request.GET)) {
try {
rsp = CachingWire.CACHE.get(this).get(
rsp = this.cache.get(
new CachingWire.Query(
this.origin, req, home, headers, content,
connect, read
Expand Down Expand Up @@ -194,7 +236,7 @@ public static void invalidate() {
*/
@ToString
@EqualsAndHashCode(of = {"origin", "request", "uri", "headers"})
private static final class Query {
private static final class Query implements Callable<Response> {
/**
* Origin wire.
*/
Expand Down Expand Up @@ -241,10 +283,12 @@ private static final class Query {
* @param rdd Read timeout
* @checkstyle ParameterNumberCheck (5 lines)
*/
Query(final Wire wire, final Request req, final String home,
Query(
final Wire wire, final Request req, final String home,
final Collection<Map.Entry<String, String>> hdrs,
final InputStream input, final int cnct,
final int rdd) {
final int rdd
) {
this.origin = wire;
this.request = req;
this.uri = home;
Expand All @@ -254,12 +298,8 @@ private static final class Query {
this.read = rdd;
}

/**
* Fetch.
* @return Response
* @throws IOException If fails
*/
public Response fetch() throws IOException {
@Override
public Response call() throws IOException {
return this.origin.send(
this.request, this.uri, Request.GET, this.headers, this.body,
this.connect, this.read
Expand Down
40 changes: 39 additions & 1 deletion src/test/java/com/jcabi/http/wire/CachingWireTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,19 @@
*/
package com.jcabi.http.wire;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.jcabi.aspects.Tv;
import com.jcabi.http.Request;
import com.jcabi.http.Response;
import com.jcabi.http.mock.MkAnswer;
import com.jcabi.http.mock.MkContainer;
import com.jcabi.http.mock.MkGrizzlyContainer;
import com.jcabi.http.request.JdkRequest;
import com.jcabi.http.response.RestResponse;
import java.net.HttpURLConnection;
import java.util.concurrent.Callable;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
Expand All @@ -45,7 +50,7 @@
* Test case for {@link CachingWire}.
* @since 1.0
*/
public final class CachingWireTest {
final class CachingWireTest {

/**
* CachingWire can cache GET requests.
Expand Down Expand Up @@ -117,4 +122,37 @@ void flushesOnRegularExpressionMatch() throws Exception {
);
}

/**
* CachingWire can use custom cache.
* @throws Exception If something goes wrong inside
*/
@Test
void cachesGetRequestWithCustomCache() throws Exception {
final MkContainer container = new MkGrizzlyContainer().next(
new MkAnswer.Simple("")
).next(
new MkAnswer.Simple(HttpURLConnection.HTTP_BAD_GATEWAY)
).start();
final LoadingCache<Callable<Response>, Response> cache =
CacheBuilder
.newBuilder()
.build(
new CacheLoader<Callable<Response>, Response>() {
@Override
public Response load(final Callable<Response> query)
throws Exception {
return query.call();
}
}
);
final Request req = new JdkRequest(container.home())
.through(CachingWire.class, cache);
for (int idx = 0; idx < Tv.TEN; ++idx) {
req.fetch().as(RestResponse.class)
.assertStatus(HttpURLConnection.HTTP_OK);
}
container.stop();
MatcherAssert.assertThat(container.queries(), Matchers.equalTo(1));
}

}

0 comments on commit cb1fef9

Please sign in to comment.