diff --git a/java/client/src/main/java/babushka/api/BaseClient.java b/java/client/src/main/java/babushka/api/BaseClient.java deleted file mode 100644 index 06cab9eec0..0000000000 --- a/java/client/src/main/java/babushka/api/BaseClient.java +++ /dev/null @@ -1,11 +0,0 @@ -package babushka.api; - -import java.util.concurrent.CompletableFuture; - -/** */ -public abstract class BaseClient { - // ConnectionManager connectionManager; - - // TODO: rename and override for resource management - public abstract CompletableFuture close(); -} diff --git a/java/client/src/main/java/babushka/api/RedisClient.java b/java/client/src/main/java/babushka/api/RedisClient.java deleted file mode 100644 index 02ec842f62..0000000000 --- a/java/client/src/main/java/babushka/api/RedisClient.java +++ /dev/null @@ -1,137 +0,0 @@ -package babushka.api; - -import static babushka.api.commands.Command.RequestType.CUSTOM_COMMAND; -import static babushka.api.commands.Command.RequestType.GETSTRING; -import static babushka.api.commands.Command.RequestType.SETSTRING; -import static babushka.api.models.commands.SetOptions.createSetOptions; - -import babushka.api.commands.BaseCommands; -import babushka.api.commands.Command; -import babushka.api.commands.StringCommands; -import babushka.api.commands.Transaction; -import babushka.api.commands.VoidCommands; -import babushka.api.models.commands.SetOptions; -import babushka.api.models.configuration.RedisClientConfiguration; -import babushka.managers.CommandManager; -import connection_request.ConnectionRequestOuterClass; -import java.lang.reflect.Array; -import java.util.LinkedList; -import java.util.concurrent.CompletableFuture; -import java.util.function.Function; -import response.ResponseOuterClass.Response; - -/** Factory class for creating Babushka-Redis client connections */ -public class RedisClient extends BaseClient - implements BaseCommands, StringCommands, VoidCommands { - - private CommandManager commandManager; - - /** - * Async (non-blocking) connection to Redis. - * - * @param config - Redis Client Configuration - * @return a promise to connect and return a RedisClient - */ - public static CompletableFuture CreateClient(RedisClientConfiguration config) { - // convert configuration to protobuf connection request - ConnectionRequestOuterClass.ConnectionRequest connectionRequest = - RequestBuilder.createConnectionRequest( - config.getHost(), config.getPort(), config.isTls(), config.isClusterMode()); - - // TODO: send request to connection manager - // return connectionManager.connectToRedis(connectionRequest); - return new CompletableFuture<>(); - } - - public RedisClient(CommandManager commandManager) { - this.commandManager = commandManager; - } - - /** - * Close the Redis client - * - * @return - */ - @Override - public CompletableFuture close() { - CompletableFuture result; - result = new CompletableFuture<>(); - result.complete(this); - return result; - } - - @Override - public CompletableFuture exec(Command command, Function responseHandler) { - return commandManager.submitNewCommand(command, responseHandler); - } - - // TODO: fix for transaction - public CompletableFuture exec(Transaction transaction) { - return new CompletableFuture<>(); - } - - /** - * Executes a single custom command, without checking inputs. Every part of the command, including - * subcommands, should be added as a separate value in args. - * - * @param cmd to be executed - * @param args arguments for the command - * @return CompletableFuture with the response - */ - public CompletableFuture customCommand(String cmd, String[] args) { - String[] commandArguments = (String[]) Array.newInstance(String.class, args.length + 1); - commandArguments[0] = cmd; - System.arraycopy(args, 0, commandArguments, 1, args.length); - - Command command = - Command.builder().requestType(CUSTOM_COMMAND).arguments(commandArguments).build(); - return exec(command, BaseCommands::handleResponse); - } - - /** - * Get the value associated with the given key, or null if no such value exists. See - * https://redis.io/commands/set/ for details. - * - * @param key - The key to retrieve from the database. - * @return If `key` exists, returns the value of `key` as a string. Otherwise, return null - */ - public CompletableFuture get(String key) { - Command command = - Command.builder().requestType(GETSTRING).arguments(new String[] {key}).build(); - return exec(command, StringCommands::handleStringResponse); - } - - /** - * Set the given key with the given value. Return value is dependent on the passed options. See - * https://redis.io/commands/set/ for details. - * - * @param key - The key to store. - * @param value - The value to store with the given key. - * @return null - */ - public CompletableFuture set(String key, String value) { - Command command = - Command.builder().requestType(SETSTRING).arguments(new String[] {key, value}).build(); - return exec(command, VoidCommands::handleVoidResponse); - } - - /** - * Set the given key with the given value. Return value is dependent on the passed options. See - * https://redis.io/commands/set/ for details. - * - * @param key - The key to store. - * @param value - The value to store with the given key. - * @param options - The Set options - * @return string or null If value isn't set because of `onlyIfExists` or `onlyIfDoesNotExist` - * conditions, return null. If `returnOldValue` is set, return the old value as a string. - */ - public CompletableFuture set(String key, String value, SetOptions options) { - LinkedList args = new LinkedList<>(); - args.add(key); - args.add(value); - args.addAll(createSetOptions(options)); - Command command = - Command.builder().requestType(SETSTRING).arguments(args.toArray(new String[0])).build(); - return exec(command, StringCommands::handleStringResponse); - } -} diff --git a/java/client/src/main/java/babushka/api/commands/BaseCommands.java b/java/client/src/main/java/babushka/api/commands/BaseCommands.java deleted file mode 100644 index f7ccfa764b..0000000000 --- a/java/client/src/main/java/babushka/api/commands/BaseCommands.java +++ /dev/null @@ -1,51 +0,0 @@ -package babushka.api.commands; - -import static babushka.ffi.resolvers.BabushkaCoreNativeDefinitions.valueFromPointer; - -import java.util.concurrent.CompletableFuture; -import java.util.function.Function; -import response.ResponseOuterClass.Response; - -public interface BaseCommands { - - /** - * Extracts value from the RESP pointer TODO: handle object if the object is small TODO: handle - * RESP2 object if configuration is set - * - * @return - */ - static Object handleResponse(Response response) { - return valueFromPointer(response.getRespPointer()); - } - - /** - * Execute a @see{Command} by sending command via socket manager - * - * @param cmd to be executed - * @param args arguments for the command - * @return a CompletableFuture with response result from Redis - */ - CompletableFuture customCommand(String cmd, String[] args); - - /** - * Execute a @see{Command} by sending command via socket manager - * - * @param command to be executed - * @return a CompletableFuture with response result from Redis - */ - CompletableFuture exec(Command command, Function responseHandler); - - /** - * Executes a transaction @see{Transaction} by sending a set of commands via socket manager - * - * @param transaction set of commands to be executed - * @return a CompletableFuture with response and a List of results from Redis TODO: change return - * value to ClusterValue - */ - CompletableFuture exec(Transaction transaction); - - public enum RequestType { - GETSTRING, - SETSTRING - } -} diff --git a/java/client/src/main/java/babushka/api/commands/Transaction.java b/java/client/src/main/java/babushka/api/commands/Transaction.java deleted file mode 100644 index 2b19f019ae..0000000000 --- a/java/client/src/main/java/babushka/api/commands/Transaction.java +++ /dev/null @@ -1,3 +0,0 @@ -package babushka.api.commands; - -public class Transaction {} diff --git a/java/client/src/main/java/babushka/api/commands/VoidCommands.java b/java/client/src/main/java/babushka/api/commands/VoidCommands.java deleted file mode 100644 index 6c17e1d4b8..0000000000 --- a/java/client/src/main/java/babushka/api/commands/VoidCommands.java +++ /dev/null @@ -1,15 +0,0 @@ -package babushka.api.commands; - -import java.util.concurrent.CompletableFuture; -import response.ResponseOuterClass; - -public interface VoidCommands { - - static Void handleVoidResponse(Object response) { - ResponseOuterClass.Response respObject = (ResponseOuterClass.Response) response; - respObject.getConstantResponse(); - return null; // Void - } - - CompletableFuture set(String key, String value); -} diff --git a/java/client/src/main/java/babushka/api/models/configuration/BaseClientConfiguration.java b/java/client/src/main/java/babushka/api/models/configuration/BaseClientConfiguration.java deleted file mode 100644 index c3218d813a..0000000000 --- a/java/client/src/main/java/babushka/api/models/configuration/BaseClientConfiguration.java +++ /dev/null @@ -1,4 +0,0 @@ -package babushka.api.models.configuration; - -/** TODO: Describe client configuration */ -public class BaseClientConfiguration {} diff --git a/java/client/src/main/java/babushka/api/models/configuration/RedisClientConfiguration.java b/java/client/src/main/java/babushka/api/models/configuration/RedisClientConfiguration.java deleted file mode 100644 index c33996baf5..0000000000 --- a/java/client/src/main/java/babushka/api/models/configuration/RedisClientConfiguration.java +++ /dev/null @@ -1,15 +0,0 @@ -package babushka.api.models.configuration; - -import lombok.Builder; -import lombok.Getter; - -/** TODO: Describe client configuration */ -@Builder -@Getter -public class RedisClientConfiguration { - - String host; - int port; - boolean isTls; - boolean clusterMode; -} diff --git a/java/client/src/main/java/babushka/api/models/exceptions/ClosingException.java b/java/client/src/main/java/babushka/api/models/exceptions/ClosingException.java deleted file mode 100644 index 0df1a75d56..0000000000 --- a/java/client/src/main/java/babushka/api/models/exceptions/ClosingException.java +++ /dev/null @@ -1,3 +0,0 @@ -package babushka.api.models.exceptions; - -public class ClosingException extends RedisException {} diff --git a/java/client/src/main/java/babushka/api/models/exceptions/ConnectionException.java b/java/client/src/main/java/babushka/api/models/exceptions/ConnectionException.java deleted file mode 100644 index ef7114cc63..0000000000 --- a/java/client/src/main/java/babushka/api/models/exceptions/ConnectionException.java +++ /dev/null @@ -1,3 +0,0 @@ -package babushka.api.models.exceptions; - -public class ConnectionException extends RedisException {} diff --git a/java/client/src/main/java/babushka/api/models/exceptions/ExecAbortException.java b/java/client/src/main/java/babushka/api/models/exceptions/ExecAbortException.java deleted file mode 100644 index 197103c6fa..0000000000 --- a/java/client/src/main/java/babushka/api/models/exceptions/ExecAbortException.java +++ /dev/null @@ -1,3 +0,0 @@ -package babushka.api.models.exceptions; - -public class ExecAbortException extends RedisException {} diff --git a/java/client/src/main/java/babushka/api/models/exceptions/RedisException.java b/java/client/src/main/java/babushka/api/models/exceptions/RedisException.java deleted file mode 100644 index e6953040bf..0000000000 --- a/java/client/src/main/java/babushka/api/models/exceptions/RedisException.java +++ /dev/null @@ -1,4 +0,0 @@ -package babushka.api.models.exceptions; - -/** TODO: does this extend RuntimeException? */ -public class RedisException {} diff --git a/java/client/src/main/java/babushka/api/models/exceptions/RequestException.java b/java/client/src/main/java/babushka/api/models/exceptions/RequestException.java deleted file mode 100644 index a43326e91d..0000000000 --- a/java/client/src/main/java/babushka/api/models/exceptions/RequestException.java +++ /dev/null @@ -1,3 +0,0 @@ -package babushka.api.models.exceptions; - -public class RequestException extends RedisException {} diff --git a/java/client/src/main/java/babushka/api/models/exceptions/TimeoutException.java b/java/client/src/main/java/babushka/api/models/exceptions/TimeoutException.java deleted file mode 100644 index 78aa2bf08c..0000000000 --- a/java/client/src/main/java/babushka/api/models/exceptions/TimeoutException.java +++ /dev/null @@ -1,3 +0,0 @@ -package babushka.api.models.exceptions; - -public class TimeoutException extends RedisException {} diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java new file mode 100644 index 0000000000..77eaea1f1c --- /dev/null +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -0,0 +1,19 @@ +package glide.api; + +import glide.managers.CommandManager; +import glide.managers.ConnectionManager; +import java.util.concurrent.CompletableFuture; +import lombok.AllArgsConstructor; + +/** + * Base Client class for Redis client + */ +@AllArgsConstructor +public abstract class BaseClient { + + protected ConnectionManager connectionManager; + protected CommandManager commandManager; + + // TODO: rename and override for resource management + public abstract CompletableFuture close(); +} diff --git a/java/client/src/main/java/glide/api/RedisClient.java b/java/client/src/main/java/glide/api/RedisClient.java new file mode 100644 index 0000000000..14275340e4 --- /dev/null +++ b/java/client/src/main/java/glide/api/RedisClient.java @@ -0,0 +1,182 @@ +package glide.api; + + +import static glide.ffi.resolvers.SocketListenerResolver.getSocket; + +import glide.api.commands.BaseCommands; +import glide.api.commands.Command; +import glide.api.commands.StringCommands; +import glide.api.commands.Transaction; +import glide.api.commands.VoidCommands; +import glide.api.models.commands.SetOptions; +import glide.api.models.configuration.NodeAddress; +import glide.api.models.configuration.RedisClientConfiguration; +import glide.api.models.exceptions.ConnectionException; +import glide.managers.CommandManager; +import glide.managers.ConnectionManager; +import glide.connectors.handlers.CallbackDispatcher; +import glide.connectors.handlers.ChannelHandler; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; +import response.ResponseOuterClass.Response; + +/** Factory class for creating Babushka-Redis client connections */ +public class RedisClient extends BaseClient + implements BaseCommands, StringCommands, VoidCommands { + + public static CompletableFuture CreateClient() { + RedisClientConfiguration config = + RedisClientConfiguration.builder() + .address(NodeAddress.builder().build()) + .useTLS(false) + .build(); + + return CreateClient(config); + } + + public static CompletableFuture CreateClient(String host, Integer port) { + RedisClientConfiguration config = + RedisClientConfiguration.builder() + .address(NodeAddress.builder().host(host).port(port).build()) + .useTLS(false) + .build(); + + return CreateClient(config); + } + + /** + * Async (non-blocking) connection to Redis. + * + * @param config - Redis Client Configuration + * @return a promise to connect and return a RedisClient + */ + public static CompletableFuture CreateClient(RedisClientConfiguration config) { + + // TODO: send request to connection manager + AtomicBoolean connectionStatus = new AtomicBoolean(false); + + CallbackDispatcher callbackDispatcher = new CallbackDispatcher(); + ChannelHandler channelHandler = new ChannelHandler(callbackDispatcher, getSocket()); + var connectionManager = new ConnectionManager(); + var commandManager = new CommandManager(); + return connectionManager + .connectToRedis( + config.getAddresses().get(0).getHost(), + config.getAddresses().get(0).getPort(), + config.isUseTLS(), + false) + .thenApplyAsync( + b -> { + if (b) { + return new RedisClient(connectionManager, commandManager); + } + throw new ConnectionException("Unable to connect to Redis"); + }); + } + + public RedisClient(ConnectionManager connectionManager, CommandManager commandManager) { + super(connectionManager, commandManager); + } + + /** + * Close the Redis client + * + * @return + */ + @Override + public CompletableFuture close() { + return connectionManager + .closeConnection() + .thenComposeAsync(ignore -> commandManager.closeConnection()) + .thenApplyAsync(ignore -> this); + } + + /** + * Execute a single command against Redis.
+ * + * @param command to be executed + * @param responseHandler handler responsible for assigning type to the response + * @return A CompletableFuture completed with the result from Redis + * @param Response value type + */ + @Override + public CompletableFuture exec(Command command, Function responseHandler) { + return commandManager.submitNewCommand(command, responseHandler); + } + + /** + * Execute a transaction by processing the queued commands.
+ * See https://redis.io/topics/Transactions/ for details on Redis Transactions.
+ * + * @param transaction with commands to be executed + * @param responseHandler handler responsible for assigning type to the list of response objects + * @return A CompletableFuture completed with the results from Redis + */ + public CompletableFuture> exec(Transaction transaction, Function> responseHandler) { + // TODO: call commandManager.submitNewTransaction() + return new CompletableFuture<>(); + } + + /** + * Executes a single custom command, without checking inputs. Every part of the command, including + * subcommands, should be added as a separate value in args. + * + * @param args command and arguments for the custom command call + * @return CompletableFuture with the response + */ + public CompletableFuture customCommand(String[] args) { + Command command = + Command.builder().requestType(Command.RequestType.CUSTOM_COMMAND).arguments(args).build(); + return exec(command, BaseCommands::handleResponse); + } + + /** + * Get the value associated with the given key, or null if no such value exists. See + * https://redis.io/commands/set/ for details. + * + * @param key - The key to retrieve from the database. + * @return If `key` exists, returns the value of `key` as a string. Otherwise, return null + */ + public CompletableFuture get(String key) { + Command command = + Command.builder().requestType(Command.RequestType.GETSTRING).arguments(new String[] {key}).build(); + return exec(command, StringCommands::handleStringResponse); + } + + /** + * Set the given key with the given value. Return value is dependent on the passed options. See + * https://redis.io/commands/set/ for details. + * + * @param key - The key to store. + * @param value - The value to store with the given key. + * @return null + */ + public CompletableFuture set(String key, String value) { + Command command = + Command.builder().requestType(Command.RequestType.SETSTRING).arguments(new String[] {key, value}).build(); + return exec(command, VoidCommands::handleVoidResponse); + } + + /** + * Set the given key with the given value. Return value is dependent on the passed options. See + * https://redis.io/commands/set/ for details. + * + * @param key - The key to store. + * @param value - The value to store with the given key. + * @param options - The Set options + * @return string or null If value isn't set because of `onlyIfExists` or `onlyIfDoesNotExist` + * conditions, return null. If `returnOldValue` is set, return the old value as a string. + */ + public CompletableFuture set(String key, String value, SetOptions options) { + LinkedList args = new LinkedList<>(); + args.add(key); + args.add(value); + args.addAll(SetOptions.createSetOptions(options)); + Command command = + Command.builder().requestType(Command.RequestType.SETSTRING).arguments(args.toArray(new String[0])).build(); + return exec(command, StringCommands::handleStringResponse); + } +} diff --git a/java/client/src/main/java/babushka/api/RequestBuilder.java b/java/client/src/main/java/glide/api/RequestBuilder.java similarity index 94% rename from java/client/src/main/java/babushka/api/RequestBuilder.java rename to java/client/src/main/java/glide/api/RequestBuilder.java index 339da5f70b..651da7371a 100644 --- a/java/client/src/main/java/babushka/api/RequestBuilder.java +++ b/java/client/src/main/java/glide/api/RequestBuilder.java @@ -1,7 +1,7 @@ -package babushka.api; +package glide.api; -import babushka.api.models.configuration.BaseClientConfiguration; -import babushka.managers.CallbackManager; +import glide.api.models.configuration.BaseClientConfiguration; +import glide.managers.CallbackManager; import connection_request.ConnectionRequestOuterClass.ConnectionRequest; import connection_request.ConnectionRequestOuterClass.NodeAddress; import connection_request.ConnectionRequestOuterClass.ReadFrom; diff --git a/java/client/src/main/java/glide/api/commands/BaseCommands.java b/java/client/src/main/java/glide/api/commands/BaseCommands.java new file mode 100644 index 0000000000..1df6cc0865 --- /dev/null +++ b/java/client/src/main/java/glide/api/commands/BaseCommands.java @@ -0,0 +1,85 @@ +package glide.api.commands; + +import static glide.ffi.resolvers.RedisValueResolver.valueFromPointer; + +import glide.api.models.exceptions.ClosingException; +import glide.api.models.exceptions.ConnectionException; +import glide.api.models.exceptions.ExecAbortException; +import glide.api.models.exceptions.RedisException; +import glide.api.models.exceptions.RequestException; +import glide.api.models.exceptions.TimeoutException; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import response.ResponseOuterClass.RequestError; +import response.ResponseOuterClass.Response; + +public interface BaseCommands { + + /** + * Extracts value from the RESP pointer + * + * @return A generic Object with the Response | null if the response is empty + */ + static Object handleResponse(Response response) { + // TODO: handle object if the object is small + // TODO: handle RESP2 object if configuration is set + if (response.hasRequestError()) { + RequestError error = response.getRequestError(); + String msg = error.getMessage(); + switch (error.getType()) { + case Unspecified: + throw new RedisException("Unexpected result: " + msg); + case ExecAbort: + throw new ExecAbortException("ExecAbortException: " + msg); + case Timeout: + throw new TimeoutException("TimeoutException: " + msg); + case Disconnect: + throw new ConnectionException("Disconnection: " + msg); + } + throw new RequestException(response.getRequestError().getMessage()); + } + if (response.hasClosingError()) { + throw new ClosingException(response.getClosingError()); + } + if (response.hasRespPointer()) { + return valueFromPointer(response.getRespPointer()); + } + if (response.hasConstantResponse()) { + // TODO: confirm + return "Ok"; + } + return null; + } + + /** + * Execute a @see{Command} by sending command via socket manager + * + * @param args arguments for the custom command + * @return a CompletableFuture with response result from Redis + */ + CompletableFuture customCommand(String[] args); + + /** + * Execute a @see{Command} by sending command via socket manager + * + * @param command to be executed + * @return a CompletableFuture with response result from Redis + */ + CompletableFuture exec(Command command, Function responseHandler); + + /** + * Execute a transaction by processing the queued commands.
+ * See https://redis.io/topics/Transactions/ for details on Redis Transactions.
+ * + * @param transaction with commands to be executed + * @param responseHandler handler responsible for assigning type to the list of response objects + * @return A CompletableFuture completed with the results from Redis + */ + CompletableFuture> exec(Transaction transaction, Function> responseHandler); + + public enum RequestType { + GETSTRING, + SETSTRING + } +} diff --git a/java/client/src/main/java/babushka/api/commands/Command.java b/java/client/src/main/java/glide/api/commands/Command.java similarity index 94% rename from java/client/src/main/java/babushka/api/commands/Command.java rename to java/client/src/main/java/glide/api/commands/Command.java index 5d4bb675dc..5e4f3ee5e2 100644 --- a/java/client/src/main/java/babushka/api/commands/Command.java +++ b/java/client/src/main/java/glide/api/commands/Command.java @@ -1,4 +1,4 @@ -package babushka.api.commands; +package glide.api.commands; import java.util.Arrays; import lombok.Builder; diff --git a/java/client/src/main/java/babushka/api/commands/StringCommands.java b/java/client/src/main/java/glide/api/commands/StringCommands.java similarity index 93% rename from java/client/src/main/java/babushka/api/commands/StringCommands.java rename to java/client/src/main/java/glide/api/commands/StringCommands.java index 9374541ef4..9a4e1422b9 100644 --- a/java/client/src/main/java/babushka/api/commands/StringCommands.java +++ b/java/client/src/main/java/glide/api/commands/StringCommands.java @@ -1,4 +1,4 @@ -package babushka.api.commands; +package glide.api.commands; import java.util.concurrent.CompletableFuture; import response.ResponseOuterClass.Response; diff --git a/java/client/src/main/java/glide/api/commands/Transaction.java b/java/client/src/main/java/glide/api/commands/Transaction.java new file mode 100644 index 0000000000..0f58cb09f0 --- /dev/null +++ b/java/client/src/main/java/glide/api/commands/Transaction.java @@ -0,0 +1,3 @@ +package glide.api.commands; + +public class Transaction {} diff --git a/java/client/src/main/java/glide/api/commands/VoidCommands.java b/java/client/src/main/java/glide/api/commands/VoidCommands.java new file mode 100644 index 0000000000..ef343b3fbb --- /dev/null +++ b/java/client/src/main/java/glide/api/commands/VoidCommands.java @@ -0,0 +1,54 @@ +package glide.api.commands; + +import glide.api.models.exceptions.ClosingException; +import glide.api.models.exceptions.ConnectionException; +import glide.api.models.exceptions.ExecAbortException; +import glide.api.models.exceptions.RedisException; +import glide.api.models.exceptions.RequestException; +import glide.api.models.exceptions.TimeoutException; +import java.util.concurrent.CompletableFuture; +import response.ResponseOuterClass.Response; +import response.ResponseOuterClass.RequestError; + +public interface VoidCommands { + + /** + * Check for errors in the Response and return null + * Throws an error if an unexpected value is returned + * + * @return null if the response is empty + */ + static Void handleVoidResponse(Object respObject) { + Response response = (Response) respObject; + if (response.hasRequestError()) { + RequestError error = response.getRequestError(); + String msg = error.getMessage(); + switch (error.getType()) { + case Unspecified: + throw new RedisException("Unexpected result: " + msg); + case ExecAbort: + throw new ExecAbortException("ExecAbortException: " + msg); + case Timeout: + throw new TimeoutException("TimeoutException: " + msg); + case Disconnect: + throw new ConnectionException("Disconnection: " + msg); + } + throw new RequestException(response.getRequestError().getMessage()); + } + if (response.hasClosingError()) { + throw new ClosingException(response.getClosingError()); + } + if (response.hasRespPointer()) { + throw new RuntimeException( + "Unexpected object returned in response - expected constantResponse or null"); + } + if (response.hasConstantResponse()) { + return null; // Void + } + // TODO commented out due to #710: empty response means a successful connection + // https://github.com/aws/babushka/issues/710 + return null; + } + + CompletableFuture set(String key, String value); +} diff --git a/java/client/src/main/java/babushka/api/models/commands/SetOptions.java b/java/client/src/main/java/glide/api/models/commands/SetOptions.java similarity index 98% rename from java/client/src/main/java/babushka/api/models/commands/SetOptions.java rename to java/client/src/main/java/glide/api/models/commands/SetOptions.java index 6b26996b16..d67e13c6c8 100644 --- a/java/client/src/main/java/babushka/api/models/commands/SetOptions.java +++ b/java/client/src/main/java/glide/api/models/commands/SetOptions.java @@ -1,4 +1,4 @@ -package babushka.api.models.commands; +package glide.api.models.commands; import java.util.LinkedList; import java.util.List; diff --git a/java/client/src/main/java/babushka/api/config/BackoffStrategy.java b/java/client/src/main/java/glide/api/models/configuration/BackoffStrategy.java similarity index 96% rename from java/client/src/main/java/babushka/api/config/BackoffStrategy.java rename to java/client/src/main/java/glide/api/models/configuration/BackoffStrategy.java index 1f316a3d21..2d3aa81bb6 100644 --- a/java/client/src/main/java/babushka/api/config/BackoffStrategy.java +++ b/java/client/src/main/java/glide/api/models/configuration/BackoffStrategy.java @@ -1,4 +1,4 @@ -package babushka.api.config; +package glide.api.models.configuration; import lombok.Builder; import lombok.Getter; diff --git a/java/client/src/main/java/babushka/api/config/BaseClientConfiguration.java b/java/client/src/main/java/glide/api/models/configuration/BaseClientConfiguration.java similarity index 97% rename from java/client/src/main/java/babushka/api/config/BaseClientConfiguration.java rename to java/client/src/main/java/glide/api/models/configuration/BaseClientConfiguration.java index 3aab953a8f..cba445a1bf 100644 --- a/java/client/src/main/java/babushka/api/config/BaseClientConfiguration.java +++ b/java/client/src/main/java/glide/api/models/configuration/BaseClientConfiguration.java @@ -1,4 +1,4 @@ -package babushka.api.config; +package glide.api.models.configuration; import java.util.List; import lombok.Builder; diff --git a/java/client/src/main/java/babushka/api/config/NodeAddress.java b/java/client/src/main/java/glide/api/models/configuration/NodeAddress.java similarity index 90% rename from java/client/src/main/java/babushka/api/config/NodeAddress.java rename to java/client/src/main/java/glide/api/models/configuration/NodeAddress.java index b034ced41f..ac4b657516 100644 --- a/java/client/src/main/java/babushka/api/config/NodeAddress.java +++ b/java/client/src/main/java/glide/api/models/configuration/NodeAddress.java @@ -1,4 +1,4 @@ -package babushka.api.config; +package glide.api.models.configuration; import lombok.Builder; import lombok.Getter; diff --git a/java/client/src/main/java/babushka/api/config/ReadFrom.java b/java/client/src/main/java/glide/api/models/configuration/ReadFrom.java similarity index 89% rename from java/client/src/main/java/babushka/api/config/ReadFrom.java rename to java/client/src/main/java/glide/api/models/configuration/ReadFrom.java index 19f8bc6e81..9792dab6c2 100644 --- a/java/client/src/main/java/babushka/api/config/ReadFrom.java +++ b/java/client/src/main/java/glide/api/models/configuration/ReadFrom.java @@ -1,4 +1,4 @@ -package babushka.api.config; +package glide.api.models.configuration; /** Represents the client's read from strategy. */ public enum ReadFrom { diff --git a/java/client/src/main/java/babushka/api/config/RedisClientConfiguration.java b/java/client/src/main/java/glide/api/models/configuration/RedisClientConfiguration.java similarity index 92% rename from java/client/src/main/java/babushka/api/config/RedisClientConfiguration.java rename to java/client/src/main/java/glide/api/models/configuration/RedisClientConfiguration.java index 4fda099233..fbdd1bba6b 100644 --- a/java/client/src/main/java/babushka/api/config/RedisClientConfiguration.java +++ b/java/client/src/main/java/glide/api/models/configuration/RedisClientConfiguration.java @@ -1,4 +1,4 @@ -package babushka.api.config; +package glide.api.models.configuration; import lombok.Getter; import lombok.experimental.SuperBuilder; diff --git a/java/client/src/main/java/babushka/api/config/RedisClusterClientConfiguration.java b/java/client/src/main/java/glide/api/models/configuration/RedisClusterClientConfiguration.java similarity index 89% rename from java/client/src/main/java/babushka/api/config/RedisClusterClientConfiguration.java rename to java/client/src/main/java/glide/api/models/configuration/RedisClusterClientConfiguration.java index 0c104427c9..ded65f1a4a 100644 --- a/java/client/src/main/java/babushka/api/config/RedisClusterClientConfiguration.java +++ b/java/client/src/main/java/glide/api/models/configuration/RedisClusterClientConfiguration.java @@ -1,4 +1,4 @@ -package babushka.api.config; +package glide.api.models.configuration; import lombok.experimental.SuperBuilder; diff --git a/java/client/src/main/java/babushka/api/config/RedisCredentials.java b/java/client/src/main/java/glide/api/models/configuration/RedisCredentials.java similarity index 92% rename from java/client/src/main/java/babushka/api/config/RedisCredentials.java rename to java/client/src/main/java/glide/api/models/configuration/RedisCredentials.java index 1d4a665247..bfcac49715 100644 --- a/java/client/src/main/java/babushka/api/config/RedisCredentials.java +++ b/java/client/src/main/java/glide/api/models/configuration/RedisCredentials.java @@ -1,4 +1,4 @@ -package babushka.api.config; +package glide.api.models.configuration; import lombok.Builder; import lombok.Getter; diff --git a/java/client/src/main/java/glide/api/models/exceptions/ClosingException.java b/java/client/src/main/java/glide/api/models/exceptions/ClosingException.java new file mode 100644 index 0000000000..49bc55200d --- /dev/null +++ b/java/client/src/main/java/glide/api/models/exceptions/ClosingException.java @@ -0,0 +1,7 @@ +package glide.api.models.exceptions; + +public class ClosingException extends RedisException { + public ClosingException(String message) { + super(message); + } +} diff --git a/java/client/src/main/java/glide/api/models/exceptions/ConnectionException.java b/java/client/src/main/java/glide/api/models/exceptions/ConnectionException.java new file mode 100644 index 0000000000..25d261a787 --- /dev/null +++ b/java/client/src/main/java/glide/api/models/exceptions/ConnectionException.java @@ -0,0 +1,7 @@ +package glide.api.models.exceptions; + +public class ConnectionException extends RedisException { + public ConnectionException(String message) { + super(message); + } +} diff --git a/java/client/src/main/java/glide/api/models/exceptions/ExecAbortException.java b/java/client/src/main/java/glide/api/models/exceptions/ExecAbortException.java new file mode 100644 index 0000000000..370743a8e3 --- /dev/null +++ b/java/client/src/main/java/glide/api/models/exceptions/ExecAbortException.java @@ -0,0 +1,7 @@ +package glide.api.models.exceptions; + +public class ExecAbortException extends RedisException { + public ExecAbortException(String message) { + super(message); + } +} diff --git a/java/client/src/main/java/glide/api/models/exceptions/RedisException.java b/java/client/src/main/java/glide/api/models/exceptions/RedisException.java new file mode 100644 index 0000000000..fbba7a88e4 --- /dev/null +++ b/java/client/src/main/java/glide/api/models/exceptions/RedisException.java @@ -0,0 +1,17 @@ +package glide.api.models.exceptions; + +/** TODO: does this extend RuntimeException? */ +public class RedisException extends RuntimeException { + + public RedisException() { super(); } + + public RedisException(String message) { super(message); } + + public RedisException(Throwable cause) { + super(cause); + } + + public RedisException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/java/client/src/main/java/glide/api/models/exceptions/RequestException.java b/java/client/src/main/java/glide/api/models/exceptions/RequestException.java new file mode 100644 index 0000000000..0e85fe21e7 --- /dev/null +++ b/java/client/src/main/java/glide/api/models/exceptions/RequestException.java @@ -0,0 +1,7 @@ +package glide.api.models.exceptions; + +public class RequestException extends RedisException { + public RequestException(String message) { + super(message); + } +} diff --git a/java/client/src/main/java/glide/api/models/exceptions/TimeoutException.java b/java/client/src/main/java/glide/api/models/exceptions/TimeoutException.java new file mode 100644 index 0000000000..bfdc365d23 --- /dev/null +++ b/java/client/src/main/java/glide/api/models/exceptions/TimeoutException.java @@ -0,0 +1,7 @@ +package glide.api.models.exceptions; + +public class TimeoutException extends RedisException { + public TimeoutException(String message) { + super(message); + } +} diff --git a/java/client/src/main/java/glide/ffi/resolvers/GlideCoreNativeDefinitions.java b/java/client/src/main/java/glide/ffi/resolvers/GlideCoreNativeDefinitions.java deleted file mode 100644 index 640ce4bd39..0000000000 --- a/java/client/src/main/java/glide/ffi/resolvers/GlideCoreNativeDefinitions.java +++ /dev/null @@ -1,34 +0,0 @@ -package glide.ffi.resolvers; - -<<<<<<<< HEAD:java/client/src/main/java/glide/ffi/resolvers/GlideCoreNativeDefinitions.java -<<<<<<<< HEAD:java/client/src/main/java/glide/ffi/resolvers/GlideCoreNativeDefinitions.java -public class GlideCoreNativeDefinitions { - public static native String startSocketListenerExternal() throws Exception; -======== -public class SocketListenerResolver { ->>>>>>>> 337bcd7 (Managers):java/client/src/main/java/glide/ffi/resolvers/SocketListenerResolver.java -======== -public class BabushkaCoreNativeDefinitions { - public static native String startSocketListenerExternal() throws Exception; ->>>>>>>> 5d172a4 (Revert "Managers"):java/client/src/main/java/glide/ffi/resolvers/BabushkaCoreNativeDefinitions.java - - public static native Object valueFromPointer(long pointer); - - static { - System.loadLibrary("glide-rs"); - } - - /** - * Make an FFI call to obtain the socket path. - * - * @return A UDS path. - */ - public static String getSocket() { - try { - return startSocketListenerExternal(); - } catch (Exception | UnsatisfiedLinkError e) { - System.err.printf("Failed to create a UDS connection: %s%n%n", e); - throw new RuntimeException(e); - } - } -} diff --git a/java/client/src/main/java/glide/ffi/resolvers/RedisValueResolver.java b/java/client/src/main/java/glide/ffi/resolvers/RedisValueResolver.java new file mode 100644 index 0000000000..9f59e16c88 --- /dev/null +++ b/java/client/src/main/java/glide/ffi/resolvers/RedisValueResolver.java @@ -0,0 +1,13 @@ +package glide.ffi.resolvers; + +import response.ResponseOuterClass.Response; + +public class RedisValueResolver { + /** + * Resolve a value received from Redis using given C-style pointer. + * + * @param pointer A memory pointer from {@link Response} + * @return A RESP3 value + */ + public static native Object valueFromPointer(long pointer); +} \ No newline at end of file diff --git a/java/client/src/main/java/glide/ffi/resolvers/SocketListenerResolver.java b/java/client/src/main/java/glide/ffi/resolvers/SocketListenerResolver.java new file mode 100644 index 0000000000..8de253fe06 --- /dev/null +++ b/java/client/src/main/java/glide/ffi/resolvers/SocketListenerResolver.java @@ -0,0 +1,25 @@ +package glide.ffi.resolvers; + +public class SocketListenerResolver { + + /** Make an FFI call to Glide to open a UDS socket to connect to. */ + private static native String startSocketListener() throws Exception; + + static { + System.loadLibrary("glide_rs"); + } + + /** + * Make an FFI call to obtain the socket path. + * + * @return A UDS path. + */ + public static String getSocket() { + try { + return startSocketListener(); + } catch (Exception | UnsatisfiedLinkError e) { + System.err.printf("Failed to create a UDS connection: %s%n%n", e); + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/java/client/src/main/java/babushka/managers/CallbackManager.java b/java/client/src/main/java/glide/managers/CallbackManager.java similarity index 95% rename from java/client/src/main/java/babushka/managers/CallbackManager.java rename to java/client/src/main/java/glide/managers/CallbackManager.java index 34d95d607c..720b84f36f 100644 --- a/java/client/src/main/java/babushka/managers/CallbackManager.java +++ b/java/client/src/main/java/glide/managers/CallbackManager.java @@ -1,6 +1,5 @@ -package babushka.managers; +package glide.managers; -import babushka.connectors.handlers.ReadHandler; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; @@ -9,7 +8,7 @@ import org.apache.commons.lang3.tuple.Pair; import response.ResponseOuterClass.Response; -/** Holder for resources required to dispatch responses and used by {@link ReadHandler}. */ +/** Holder for resources required to dispatch responses and used by ReadHandler. */ public class CallbackManager { /** Unique request ID (callback ID). Thread-safe. */ private final AtomicInteger requestId = new AtomicInteger(0); diff --git a/java/client/src/main/java/babushka/managers/CommandManager.java b/java/client/src/main/java/glide/managers/CommandManager.java similarity index 77% rename from java/client/src/main/java/babushka/managers/CommandManager.java rename to java/client/src/main/java/glide/managers/CommandManager.java index cf9f4b9144..f409bce6c4 100644 --- a/java/client/src/main/java/babushka/managers/CommandManager.java +++ b/java/client/src/main/java/glide/managers/CommandManager.java @@ -1,6 +1,6 @@ -package babushka.managers; +package glide.managers; -import babushka.api.commands.Command; +import glide.api.commands.Command; import java.util.concurrent.CompletableFuture; import java.util.function.Function; import response.ResponseOuterClass.Response; @@ -20,4 +20,8 @@ public CompletableFuture submitNewCommand( // handle return type in the thenApplyAsync return new CompletableFuture<>(); } + + public CompletableFuture closeConnection() { + return new CompletableFuture<>(); + } } diff --git a/java/client/src/main/java/glide/managers/ConnectionManager.java b/java/client/src/main/java/glide/managers/ConnectionManager.java new file mode 100644 index 0000000000..579b679165 --- /dev/null +++ b/java/client/src/main/java/glide/managers/ConnectionManager.java @@ -0,0 +1,15 @@ +package glide.managers; + +import java.util.concurrent.CompletableFuture; + +public class ConnectionManager { + + public CompletableFuture connectToRedis( + String host, int port, boolean useSsl, boolean clusterMode) { + return new CompletableFuture<>(); + } + + public CompletableFuture closeConnection() { + return new CompletableFuture<>(); + } +} diff --git a/java/client/src/test/java/babushka/api/RedisClientTest.java b/java/client/src/test/java/babushka/api/RedisClientTest.java index 02644d7bee..15f5dca6af 100644 --- a/java/client/src/test/java/babushka/api/RedisClientTest.java +++ b/java/client/src/test/java/babushka/api/RedisClientTest.java @@ -1,10 +1,10 @@ package babushka.api; -import static babushka.api.models.commands.SetOptions.CONDITIONAL_SET_ONLY_IF_DOES_NOT_EXIST; -import static babushka.api.models.commands.SetOptions.CONDITIONAL_SET_ONLY_IF_EXISTS; -import static babushka.api.models.commands.SetOptions.RETURN_OLD_VALUE; -import static babushka.api.models.commands.SetOptions.TIME_TO_LIVE_KEEP_EXISTING; -import static babushka.api.models.commands.SetOptions.TIME_TO_LIVE_UNIX_SECONDS; +import static glide.api.models.commands.SetOptions.CONDITIONAL_SET_ONLY_IF_DOES_NOT_EXIST; +import static glide.api.models.commands.SetOptions.CONDITIONAL_SET_ONLY_IF_EXISTS; +import static glide.api.models.commands.SetOptions.RETURN_OLD_VALUE; +import static glide.api.models.commands.SetOptions.TIME_TO_LIVE_KEEP_EXISTING; +import static glide.api.models.commands.SetOptions.TIME_TO_LIVE_UNIX_SECONDS; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -14,10 +14,12 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import babushka.api.commands.Command; -import babushka.api.models.commands.SetOptions; -import babushka.api.models.configuration.RedisClientConfiguration; -import babushka.managers.CommandManager; +import glide.api.RedisClient; +import glide.api.commands.Command; +import glide.api.models.commands.SetOptions; +import glide.api.models.configuration.RedisClientConfiguration; +import glide.managers.CommandManager; +import glide.managers.ConnectionManager; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.junit.jupiter.api.BeforeEach; @@ -27,22 +29,16 @@ public class RedisClientTest { RedisClient service; + ConnectionManager connectionManager; CommandManager commandManager; - private static String HOST = "host"; private static int PORT = 9999; @BeforeEach public void setUp() { - RedisClientConfiguration configuration = - RedisClientConfiguration.builder() - .host(HOST) - .port(PORT) - .isTls(false) - .clusterMode(false) - .build(); + connectionManager = mock(ConnectionManager.class); commandManager = mock(CommandManager.class); - service = new RedisClient(commandManager); + service = new RedisClient(connectionManager, commandManager); } @Test @@ -56,7 +52,7 @@ public void customCommand_success() throws ExecutionException, InterruptedExcept when(commandManager.submitNewCommand(any(), any())).thenReturn(testResponse); // exercise - CompletableFuture response = service.customCommand(cmd, new String[] {key}); + CompletableFuture response = service.customCommand(new String[] {cmd, key}); String payload = (String) response.get(); // verify