diff --git a/momento-sdk/src/intTest/java/momento/sdk/CacheTest.java b/momento-sdk/src/intTest/java/momento/sdk/CacheTest.java index 248370aa..48b2c61f 100644 --- a/momento-sdk/src/intTest/java/momento/sdk/CacheTest.java +++ b/momento-sdk/src/intTest/java/momento/sdk/CacheTest.java @@ -101,9 +101,9 @@ private static void testHappyPath(Cache cache) { assertEquals(MomentoCacheResult.Ok, setRsp.getResult()); // Get Key that was just set - ClientGetResponse rsp = cache.get(key); + ClientGetResponse rsp = cache.get(key); assertEquals(MomentoCacheResult.Hit, rsp.getResult()); - assertEquals("bar", StandardCharsets.US_ASCII.decode(rsp.getBody()).toString()); + assertEquals("bar", rsp.asStringUtf8()); } @Test @@ -131,10 +131,10 @@ private static void testAsyncHappyPath(Cache client) throws Exception { assertEquals(MomentoCacheResult.Ok, setRsp.toCompletableFuture().get().getResult()); // Get Key Async - ClientGetResponse rsp = client.getAsync(key).toCompletableFuture().get(); + ClientGetResponse rsp = client.getAsync(key).toCompletableFuture().get(); assertEquals(MomentoCacheResult.Hit, rsp.getResult()); - assertEquals("bar", StandardCharsets.US_ASCII.decode(rsp.getBody()).toString()); + assertEquals("bar", rsp.asStringUtf8()); } @Test @@ -165,7 +165,7 @@ private static void testTtlHappyPath(Cache client) throws Exception { Thread.sleep(1500); // Get Key that was just set - ClientGetResponse rsp = client.get(key); + ClientGetResponse rsp = client.get(key); assertEquals(MomentoCacheResult.Miss, rsp.getResult()); } @@ -188,7 +188,7 @@ void testMissHappyPathWithTracing() throws Exception { private static void testMissHappyPathInternal(Cache client) { // Get Key that was just set - ClientGetResponse rsp = client.get(UUID.randomUUID().toString()); + ClientGetResponse rsp = client.get(UUID.randomUUID().toString()); assertEquals(MomentoCacheResult.Miss, rsp.getResult()); } diff --git a/momento-sdk/src/intTest/java/momento/sdk/MomentoTest.java b/momento-sdk/src/intTest/java/momento/sdk/MomentoTest.java index a20a7b59..569bb958 100644 --- a/momento-sdk/src/intTest/java/momento/sdk/MomentoTest.java +++ b/momento-sdk/src/intTest/java/momento/sdk/MomentoTest.java @@ -56,9 +56,9 @@ void testHappyPath() { assertEquals(MomentoCacheResult.Ok, setRsp.getResult()); // Get Key that was just set - ClientGetResponse rsp = cache.get(key); + ClientGetResponse rsp = cache.get(key); assertEquals(MomentoCacheResult.Hit, rsp.getResult()); - assertEquals("bar", StandardCharsets.US_ASCII.decode(rsp.getBody()).toString()); + assertEquals("bar", rsp.asStringUtf8()); } // TODO: Update this to be recreated each time and add a separate test case for Already Exists diff --git a/momento-sdk/src/main/java/momento/sdk/Cache.java b/momento-sdk/src/main/java/momento/sdk/Cache.java index 2dfc6e3b..7db361e5 100644 --- a/momento-sdk/src/main/java/momento/sdk/Cache.java +++ b/momento-sdk/src/main/java/momento/sdk/Cache.java @@ -24,7 +24,6 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.ImplicitContextKeyed; import io.opentelemetry.context.Scope; -import java.io.ByteArrayInputStream; import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; @@ -36,7 +35,6 @@ import java.util.concurrent.CompletionStage; import javax.net.ssl.SSLException; import momento.sdk.exceptions.CacheServiceExceptionMapper; -import momento.sdk.exceptions.ClientSdkException; import momento.sdk.messages.ClientGetResponse; import momento.sdk.messages.ClientSetResponse; @@ -135,17 +133,15 @@ public Cache( * java.util.concurrent.CompletionStage} returned instead. * * @param key the key of item to fetch from cache - * @return {@link ClientGetResponse} with the response object as a {@link java.nio.ByteBuffer} + * @return {@link ClientGetResponse} with the response object * @throws IOException if an error occurs opening input stream for response body. */ - public ClientGetResponse get(String key) { + public ClientGetResponse get(String key) { Optional span = buildSpan("java-sdk-get-request"); try (Scope ignored = (span.map(ImplicitContextKeyed::makeCurrent).orElse(null))) { GetResponse rsp = blockingStub.get(buildGetRequest(key)); - - ByteBuffer body = rsp.getCacheBody().asReadOnlyByteBuffer(); - ClientGetResponse clientGetResponse = - new ClientGetResponse<>(rsp.getResult(), body); + ClientGetResponse clientGetResponse = + new ClientGetResponse(rsp.getResult(), rsp.getCacheBody()); span.ifPresent(theSpan -> theSpan.setStatus(StatusCode.OK)); return clientGetResponse; } catch (Exception e) { @@ -172,6 +168,18 @@ public ClientGetResponse get(String key) { * @throws IOException if an error occurs opening ByteBuffer for request body. */ public ClientSetResponse set(String key, ByteBuffer value, int ttlSeconds) { + return set(convert(key), convert(value), ttlSeconds); + } + + public ClientSetResponse set(String key, String value, int ttlSeconds) { + return set(convert(key), convert(value), ttlSeconds); + } + + public ClientSetResponse set(byte[] key, byte[] value, int ttlSeconds) { + return set(convert(key), convert(value), ttlSeconds); + } + + private ClientSetResponse set(ByteString key, ByteString value, int ttlSeconds) { Optional span = buildSpan("java-sdk-set-request"); try (Scope ignored = (span.map(ImplicitContextKeyed::makeCurrent).orElse(null))) { SetResponse rsp = blockingStub.set(buildSetRequest(key, value, ttlSeconds * 1000)); @@ -200,15 +208,15 @@ public ClientSetResponse set(String key, ByteBuffer value, int ttlSeconds) { * CompletionStage interface wrapping standard ClientResponse with response object as a {@link * java.io.InputStream}. */ - public CompletionStage> getAsync(String key) { + public CompletionStage getAsync(String key) { Optional span = buildSpan("java-sdk-get-request"); Optional scope = (span.map(ImplicitContextKeyed::makeCurrent)); // Submit request to non-blocking stub ListenableFuture rspFuture = futureStub.get(buildGetRequest(key)); // Build a CompletableFuture to return to caller - CompletableFuture> returnFuture = - new CompletableFuture>() { + CompletableFuture returnFuture = + new CompletableFuture() { @Override public boolean cancel(boolean mayInterruptIfRunning) { // propagate cancel to the listenable future if called on returned completable future @@ -224,8 +232,7 @@ public boolean cancel(boolean mayInterruptIfRunning) { new FutureCallback() { @Override public void onSuccess(GetResponse rsp) { - ByteBuffer body = rsp.getCacheBody().asReadOnlyByteBuffer(); - returnFuture.complete(new ClientGetResponse<>(rsp.getResult(), body)); + returnFuture.complete(new ClientGetResponse(rsp.getResult(), rsp.getCacheBody())); span.ifPresent( theSpan -> { theSpan.setStatus(StatusCode.OK); @@ -265,6 +272,7 @@ public void onFailure(Throwable e) { * CompletionStage interface wrapping standard ClientSetResponse. * @throws IOException if an error occurs opening ByteBuffer for request body. */ + // TODO: Update Async methods to support different input params. public CompletionStage setAsync(String key, ByteBuffer value, int ttlSeconds) { Optional span = buildSpan("java-sdk-set-request"); @@ -272,7 +280,7 @@ public CompletionStage setAsync(String key, ByteBuffer value, // Submit request to non-blocking stub ListenableFuture rspFuture = - futureStub.set(buildSetRequest(key, value, ttlSeconds * 1000)); + futureStub.set(buildSetRequest(convert(key), convert(value), ttlSeconds * 1000)); // Build a CompletableFuture to return to caller CompletableFuture returnFuture = @@ -331,16 +339,24 @@ private GetRequest buildGetRequest(String key) { .build(); } - private SetRequest buildSetRequest(String key, ByteBuffer value, int ttl) { - try { - return SetRequest.newBuilder() - .setCacheKey(ByteString.copyFrom(key, StandardCharsets.UTF_8)) - .setCacheBody(ByteString.readFrom(new ByteArrayInputStream(value.array()))) - .setTtlMilliseconds(ttl) - .build(); - } catch (IOException e) { - throw new ClientSdkException("Failed to create request."); - } + private SetRequest buildSetRequest(ByteString key, ByteString value, int ttl) { + return SetRequest.newBuilder() + .setCacheKey(key) + .setCacheBody(value) + .setTtlMilliseconds(ttl) + .build(); + } + + private ByteString convert(String stringToEncode) { + return ByteString.copyFromUtf8(stringToEncode); + } + + private ByteString convert(byte[] bytes) { + return ByteString.copyFrom(bytes); + } + + private ByteString convert(ByteBuffer byteBuffer) { + return ByteString.copyFrom(byteBuffer); } private Optional buildSpan(String spanName) { diff --git a/momento-sdk/src/main/java/momento/sdk/exceptions/SdkException.java b/momento-sdk/src/main/java/momento/sdk/exceptions/SdkException.java index 6989b554..7157374e 100644 --- a/momento-sdk/src/main/java/momento/sdk/exceptions/SdkException.java +++ b/momento-sdk/src/main/java/momento/sdk/exceptions/SdkException.java @@ -5,7 +5,6 @@ public class SdkException extends RuntimeException { public SdkException(String message, Throwable cause) { super(message, cause); - this.initCause(cause); } public SdkException(String message) { diff --git a/momento-sdk/src/main/java/momento/sdk/messages/ClientGetResponse.java b/momento-sdk/src/main/java/momento/sdk/messages/ClientGetResponse.java index eeacdec8..a2130ce1 100644 --- a/momento-sdk/src/main/java/momento/sdk/messages/ClientGetResponse.java +++ b/momento-sdk/src/main/java/momento/sdk/messages/ClientGetResponse.java @@ -1,12 +1,14 @@ package momento.sdk.messages; +import com.google.protobuf.ByteString; import grpc.cache_client.ECacheResult; +import java.nio.ByteBuffer; -public final class ClientGetResponse extends BaseResponse { - private final T body; +public final class ClientGetResponse extends BaseResponse { + private final ByteString body; private final ECacheResult result; - public ClientGetResponse(ECacheResult result, T body) { + public ClientGetResponse(ECacheResult result, ByteString body) { this.body = body; this.result = result; } @@ -15,7 +17,20 @@ public MomentoCacheResult getResult() { return this.resultMapper(this.result); } - public T getBody() { - return body; + public byte[] asByteArray() { + return body.toByteArray(); + } + + public ByteBuffer asByteBuffer() { + return body.asReadOnlyByteBuffer(); + } + + /** + * Converts the value read from cache to a UTF-8 String + * + * @return + */ + public String asStringUtf8() { + return body.toStringUtf8(); } }